所谓网游,不过是场戏精鉴赏

转载请注脚原文地址:http://www.cnblogs.com/LadyLex/p/8006488.html 

为了在娱乐中体会一把“仗(bu)剑(fu)快(jiu)意(shi)江(gan)湖”的淋漓快感,入帮成为了好多“人头狗”的不二增选。

Input

  第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行六个整数a,
b,
意味着房间a与房间b之间有一条走廊相连。接下来一行包含一个平头Q,表示操作次数。接着Q行,每行一个操作,如
上文所示。

然而入帮未来才发现,剑三帮会简直就是现实性社会的缩影,你能在此处看到社会的戏精百态,也能把真情江湖生生玩成戏精江湖。

Sample Output

4
3
3
4

攻防排队就是一群戏精的公共表演

假使说每一个职场人都在为 KPI 没日没夜加班奋斗,那么 DKP 就是剑三 PVP
玩家的人生追求。

DKP(Dragon Kill Point 屠龙积分)源自游戏《无尽的任务》,龙代表游戏的大
BOSS,屠龙积分成为衡量玩家屠龙业绩的科班。

新生这一定义被广泛应用于网络游戏中,剑三中帮主会遵照成员为帮会做出的孝敬(即
DKP)发放相应奖励。

除却帮战、扫图和沙场,DKP 最快得到形式依旧得靠每一周日次的大大小小攻防。

出于剑三攻防期间每个地图都有食指上限,上午8点起来的攻防,一般早上5点即将起来排队进图,倘使地图人满了再想进入,就不得不希望图里玩家网卡掉线了。

图片来源:多玩游戏

有段时光,剑三某服的两大阵营仇恨值太高,咱们都跟打了鸡血一样,打攻防的心绪空前高涨,直接导致排队时间又超前几刻钟。

下午两点不到,很多地图已经满额告急 

只要我们都能拿出打攻防的积极性去做项目,还愁总经理不给你升职加薪吗?

HINT

 满意 n<=150000,Q<=200000。对于持有数据,满足 A<=10^9

 

今日您应有能体悟咋做了吗!

俺们用数据结构维护以i为分治树根的子树每个年龄的精灵到i的偏离,以及到i分治树大爷的相距,然后用数据结构求和。

数据结构用哪些啊?线段树?$O(nlog^{2}n)$的半空中复杂度肯定会MLE的。

专注到这多少个求和可以写为前缀和相减的花样,因而我们用可以用$O(nlogn)$的长空复杂度的vector+sort排序节省内存。

那么这道题就被解决啦……代码见下:

图片 1图片 2

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <vector>
  4 #include <algorithm>
  5 using namespace std;
  6 #define N 150010
  7 #define LL long long
  8 int n,e,tot,adj[N],q,maxn,val[N];
  9 char B[1<<15],*S=B,*T=B;
 10 #define getc (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
 11 inline int read()
 12 {
 13     int x=0;register char c=getc;
 14     while(c<'0'||c>'9')c=getc;
 15     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
 16     return x;
 17 }
 18 #define min(a,b) ((a)<(b)?(a):(b))
 19 #define max(a,b) ((a)>(b)?(a):(b))
 20 struct edge{int zhong,next,val;}s[N<<1];
 21 inline void add(int qi,int zhong,int val)
 22     {s[++e].zhong=zhong,s[e].val=val,s[e].next=adj[qi],adj[qi]=e;}
 23 int f[N<<1][19],deep[N],dfn[N],num,bin[25],tp,logn[N<<1];
 24 inline void ST()
 25 {
 26     for(int i=1;i<=tp;++i)
 27         for(int j=1;j+bin[i]-1<=(n<<1);++j)
 28             f[j][i]=min(f[j][i-1],f[j+bin[i-1]][i-1]);
 29 }
 30 inline void dfs1(int rt,int fa,int len)
 31 {
 32     f[(dfn[rt]=++num)][0]=deep[rt]=len;
 33     for(int i=adj[rt];i;i=s[i].next)
 34         if(s[i].zhong!=fa)
 35             dfs1(s[i].zhong,rt,len+s[i].val),f[++num][0]=len;
 36 }
 37 int Vater[N],size[N],maxs[N],totsize,root;
 38 bool vis[N];
 39 inline void dfs2(int rt,int fa)
 40 {
 41     size[rt]=1,maxs[rt]=0;
 42     for(int i=adj[rt];i;i=s[i].next)
 43         if(!vis[s[i].zhong]&&s[i].zhong!=fa)
 44             dfs2(s[i].zhong,rt),size[rt]+=size[s[i].zhong],
 45             maxs[rt]=max(maxs[rt],size[s[i].zhong]);
 46     maxs[rt]=max(maxs[rt],totsize-size[rt]);
 47     if(maxs[rt]<maxs[root])root=rt;
 48 }
 49 inline LL dis(int a,int b)
 50 {
 51     if(dfn[a]>dfn[b])a^=b,b^=a,a^=b;
 52     int k=logn[dfn[b]-dfn[a]+1];
 53     return deep[a]+deep[b]-(min(f[dfn[a]][k],f[dfn[b]-bin[k]+1][k])<<1);
 54 }
 55 struct node
 56 {
 57     int val;LL size[3];
 58     node(int a=0,LL b=0,LL c=0,LL d=0){val=a,size[0]=b,size[1]=c,size[2]=d;}
 59     inline bool operator < (const node &b)const
 60         {return val<b.val;}
 61 };
 62 vector<node>sta[N];
 63 inline void dfs3(int rt,int fa,int Vatti)
 64 {
 65     sta[Vatti].push_back(node(val[rt],1,dis(rt,Vatti), Vater[Vatti]?dis(rt,Vater[Vatti]):0 ));
 66     for(int i=adj[rt];i;i=s[i].next)
 67         if(s[i].zhong!=fa&&!vis[s[i].zhong])
 68             dfs3(s[i].zhong,rt,Vatti);
 69 }
 70 inline void dfs4(int rt,int fa)
 71 {
 72     Vater[rt]=fa,vis[rt]=1;
 73     int siz=totsize;
 74     dfs3(rt,0,rt);sta[rt].push_back(node(-1,0,0,0));
 75     sort(sta[rt].begin(),sta[rt].end());
 76     for(int i=0,j=sta[rt].size();i<j-1;++i)
 77         sta[rt][i+1].size[0]+=sta[rt][i].size[0],
 78         sta[rt][i+1].size[1]+=sta[rt][i].size[1],
 79         sta[rt][i+1].size[2]+=sta[rt][i].size[2];
 80     for(int i=adj[rt];i;i=s[i].next)
 81         if(!vis[s[i].zhong])
 82         {
 83             if(size[s[i].zhong]>size[rt])totsize=siz-size[rt];
 84             else totsize=size[s[i].zhong];
 85             root=0,dfs2(s[i].zhong,0),dfs4(root,rt);
 86         }
 87 }
 88 inline node query(int id,int l,int r)
 89 {
 90     if(id==0)return node();
 91     vector<node>::iterator it1=upper_bound(sta[id].begin(),sta[id].end(),node(r,0,0,0) );--it1;
 92     vector<node>::iterator it2=upper_bound(sta[id].begin(),sta[id].end(),node(l-1,0,0,0));--it2;
 93     return node(0,it1->size[0]-it2->size[0],it1->size[1]-it2->size[1],it1->size[2]-it2->size[2]);
 94 }
 95 inline LL calc(int rt,int l,int r)
 96 {
 97     LL ret=0;
 98     // printf("rt=%d l=%d r=%d\n",rt,l,r);
 99     for(int x=rt;x;x=Vater[x])
100     {
101         node a=query(x,l,r);
102         ret+=a.size[1];
103         if(x!=rt)ret+=a.size[0]*dis(x,rt);
104         if(Vater[x])ret-=a.size[2]+a.size[0]*dis(Vater[x],rt);
105     }
106     return ret;
107 }
108 int main()
109 {
110     register int i,j,a,b,c;LL ans=0;
111     n=read(),q=read(),maxn=read();
112     for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1;
113     while(bin[tp+1]<=(n<<1))++tp;
114     for(logn[0]=-1,i=1;i<=(n<<1);++i)logn[i]=logn[i>>1]+1;
115     for(i=1;i<=n;++i)val[i]=read();
116     for(i=1;i<n;++i)
117         a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c);
118     dfs1(1,0,0),ST();
119     root=0,maxs[0]=n+1,totsize=n,dfs2(1,0);
120     dfs4(root,0);
121     while(q--)
122     {
123         a=read(),b=read(),c=read();
124         b=(b+ans)%maxn,c=(c+ans)%maxn;
125         if(b>c)b^=c,c^=b,b^=c;
126         printf("%lld\n",ans=calc(a,b,c));
127     }
128 }

BZOJ4012

说到底大家来个大boss试试知难♂而上

 

图形来自:@伊吹鸡腿子

Sample Input

5
1 2 1
1 3 2
1 4 1
2 5 3

为了让玩家深切感受腥风血雨的波动江湖、盘根错节的武林势力,《剑侠情缘网络版3》(简称《剑三》)划分了两大阵营——浩气盟和恶人谷。

Sample Input

10 10 10
0 0 7 2 1 4 7 7 7 9
1 2 270
2 3 217
1 4 326
2 5 361
4 6 116
3 7 38
1 8 800
6 9 210
7 10 278
8 9 8
2 8 0
9 3 1
8 0 8
4 2 7
9 7 3
4 7 0
2 2 7
3 2 1
2 3 4

游玩设定了一名目繁多引战活动,生生让不同阵营的玩家变为了敌人,战火已经从上百人的攻防团战蔓延到野外抢怪和跑商劫镖。

Sample Input

0
5
0 0 6
1 2 4
0 9 4
0 5 5
0 2 4 

帮会中戏精管理的高位之道,堪比职场宫心计

借使说挂上一个阵营排行前三的帮会称谓,能让你在野外横着走,那么进入这么些大帮的管理层相对能让您感受到“一呼百应、众人珍重”的快感。

稍稍人为了“上位”,也是没法子心机、用尽手段,硬是将一个武侠游戏玩成了甄嬛传。

数年前,某电信大服的地痞势力有个相当大的帮会,几乎是同盟“杠把子”。这么些大帮的某位妹子管理经常显示卓殊活跃,通常主动拉拢各路犀利玩家入帮,帮会扩充之际便成为了分帮的帮主。

不过没过多长时间便有人在贴吧爆料:

该女通过各个挑唆挑唆,破坏大帮主和各层管理的关系,达到上位目标。还有人扒出他的情缘竟是对峙阵营大帮的管制,计划通过她引导着新的帮会来占坑、当艺人,从而获取阵营攻防的常胜。

大帮水太深,依旧安心地做个小透明吗

Sample Output

0
1
4
5
6

 

怎么操作呢?我们不难察觉,由于目标函数是$Σd_{v}*dis(u,v)$,由定义可知,大家的对象其实就是求带权的侧重点

那么怎么求呢……依旧先虽然我们有一棵静态的树,那么考虑树规。

想转手树规中大家都求了如何:

设$s1[i]$为i子树点权和,$s2[i]$为i子树点到它的相距和,$s3[i]$为i岳父到它的距离和。

那么转移应该是

$ans[i]=ans[fa]+s2[fa]-s2[i]-s1[i]*dis(i,fa)+s3[fa]+(sum-s1[i])*dis(i,fa)$

dis大家可以用ST表RMQ或者倍增LCA来求.

但骨子里我们是足以不要s3数组,一层一层跳着往上求$s2[fa]-s2[i]-s1[i]*dis(i,fa)$这个姿势的。

是因为原树可能是条链,大家不敢直接跳,只可以维护s3数组。

只是如若改动的话,s3涉及到的修改会特别多!

大家联想到,分治树的惊人是$logn$的!

之所以我们得以不维护s3,仅仅维护s1和s2,在分治树上用$O(logn)$的刻钟求出某一个点作为带权重心时的权和。

但是你会发现,大家地点的姿势里有一个-s2[i]很难处理:在树规中i和fa只隔了一条边,可是在分治树中,你并不知道元素长什么样子!

之所以我们依然得加一个s3数组,s3[i]表示i的分治树子节点到i分治树四伯的权和。这就是大家动态树分治中“保安岳丈”思想的出众体现

那就是说大家现在就可以以$O(logn)$的复杂度枚举i的祖先fa,求$Σs2[fa]-s3[i]+(s1[fa]-s1[i])*dis(i,fa)$来求与i在原树上的lca是fa的点到i的离开了。

*这种$O(logn)$跳父亲的做法也是一种普遍的沉思。

然后对于总结答案,我们得以每一趟从分治树的根出发,看往他的哪位外侄子走答案更优。

俺们最多走$logn$层,每一层最多开展20次$O(logn)$的乘除,由此查询是$O(20log^{2}n)$的.

总的复杂度$O(20Qlog^{2}n)$。代码见下:

图片 3图片 4

  1 #include <cstdio>
  2 #include <cstring>
  3 using namespace std;
  4 #define LL long long
  5 #define N 100010
  6 #define LL long long
  7 #define max(a,b) ((a)>(b)?(a):(b))
  8 #define min(a,b) ((a)<(b)?(a):(b))
  9 struct edge{int zhong,next,val;};
 10 struct G
 11 {
 12     edge s[N<<1];int e,adj[N];
 13     G(){e=0;memset(adj,0,sizeof(adj));}
 14     inline void add(int qi,int zhong,int val=0)
 15         {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;s[e].val=val;}
 16 }T1,T2;
 17 int n,q,f[N<<1][18],logn[N<<1],bin[25],tp;
 18 LL s[3][N],sum,ans,len[N];
 19 int dfn[N],num;
 20 inline void dfs1(int rt,int fa)
 21 {
 22     f[(dfn[rt]=++num)][0]=len[rt];
 23     for(int i=T1.adj[rt];i;i=T1.s[i].next)
 24         if(T1.s[i].zhong!=fa)
 25             len[T1.s[i].zhong]=len[rt]+T1.s[i].val,dfs1(T1.s[i].zhong,rt),f[++num][0]=len[rt];
 26 }
 27 inline LL LCA(int a,int b)
 28 {
 29     if(dfn[a]>dfn[b])a^=b,b^=a,a^=b;
 30     int k=logn[dfn[b]-dfn[a]+1];
 31     return min(f[dfn[a]][k],f[dfn[b]-bin[k]+1][k])<<1;
 32 }
 33 inline LL dis(int a,int b){return len[a]+len[b]-LCA(a,b);}
 34 int size[N],maxs[N],totsize,root,Vater[N];
 35 bool vis[N];
 36 inline void dfs2(int rt,int fa)
 37 {
 38     size[rt]=1,maxs[rt]=0;
 39     for(int i=T1.adj[rt];i;i=T1.s[i].next)
 40         if(!vis[T1.s[i].zhong]&&T1.s[i].zhong!=fa)
 41             dfs2(T1.s[i].zhong,rt),size[rt]+=size[T1.s[i].zhong],
 42             maxs[rt]=max(size[T1.s[i].zhong],maxs[rt]);
 43     maxs[rt]=max(totsize-size[rt],maxs[rt]);
 44     if(maxs[rt]<maxs[root])root=rt;
 45 }
 46 inline void dfs3(int rt,int fa)
 47 {
 48     Vater[rt]=fa;vis[rt]=1;int siz=totsize;
 49     for(int i=T1.adj[rt];i;i=T1.s[i].next)
 50         if(!vis[T1.s[i].zhong])
 51         {
 52             if(size[T1.s[i].zhong]>size[rt])totsize=siz-size[rt];
 53             else totsize=size[T1.s[i].zhong];
 54             root=0,dfs2(T1.s[i].zhong,0),T2.add(rt,root,T1.s[i].zhong),dfs3(root,rt);
 55         }
 56 }
 57 inline void update(int who,LL val)
 58 {
 59     for(int rt=who;rt;rt=Vater[rt])
 60     {
 61         s[0][rt]+=val,s[1][rt]+=dis(rt,who)*val;
 62         if(Vater[rt])s[2][rt]+=dis(Vater[rt],who)*val;
 63     }
 64 }
 65 inline LL calc(int rt)
 66 {
 67     LL ret=0;
 68     for(int x=rt;x;x=Vater[x])
 69     {
 70         ret+=s[1][x];
 71         if(Vater[x])ret+=-s[2][x]+(s[0][Vater[x]]-s[0][x])*dis(Vater[x],rt);
 72     }
 73     return ret;
 74 }
 75 inline LL getans(int rt)
 76 {
 77     LL temp=calc(rt);
 78     for(int i=T2.adj[rt];i;i=T2.s[i].next)
 79         if(calc(T2.s[i].val)<temp)return getans(T2.s[i].zhong);//*******
 80     return temp;
 81 }
 82 char B[1<<15],*S=B,*T=B;
 83 #define getc ( S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
 84 inline int read()
 85 {
 86     int x=0,f=1;register char c=getc;
 87     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getc;}
 88     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
 89     return x*f;
 90 }
 91 int main()
 92 {
 93     register int i,j,orig,a,b,c;
 94     n=read();q=read();
 95     for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1;
 96     while(bin[tp+1]<=(n<<1))++tp;
 97     for(logn[0]=-1,i=1;i<=(n<<1);++i)logn[i]=logn[i>>1]+1;
 98     for(i=1;i<n;++i)
 99         a=read(),b=read(),c=read(),T1.add(a,b,c),T1.add(b,a,c);
100     dfs1(1,0),root=0,maxs[0]=n+1,totsize=n,dfs2(1,0);
101     for(i=1;i<=tp;++i)
102         for(j=1;j+bin[i]-1<=(n<<1);++j)
103             f[j][i]=min(f[j][i-1],f[j+bin[i-1]][i-1]);
104     orig=root,dfs3(root,0);
105     while(q--)
106         a=read(),b=read(),update(a,b),printf("%lld\n",getans(orig));
107 }

BZOJ4012

 我们再来一道焦作小异的题目:

戏精帮主的最大特征就是爱开会

除却每一周例会,还要开各个大小攻防总括会,新人入帮欢迎会,还有骚动时的 YY
歌会。

先前总抱怨工作时领导没事儿就喜爱拉人开会,自从玩了这游戏后,发现官员突然变得和蔼可亲了成千上万。

图形来源于:剑网三呢

俗话说上有政策,下有对策。有些人吸引线上会议的狐狸尾巴,YY在帮会频道挂着,然后静音去浪副本或者竞赛场。

殊不晓得高一尺,魔高一丈,帮主那些大魔王也是变着法地查看帮众们是不是在开会的时候背着他搞工作。其“反静音反挂机”的伎俩之丰硕,玩法之奇葩甚至已经到了天怒人怨的档次。

据贴吧朋友显露,他们帮主初始依旧随机点名:“XXX,你来分析一下大家本次据点掉了问题在哪儿。”

随即是大范围互动:“重阳节便于,帮里不吃五仁月饼的公屏打个1”;

再然后一度衍生和变化成歌曲接龙,一人唱一句这种。

有网友总括了弹指间帮里开会的骨干流程:

只想唱:“简单点,开会的艺术简单点” 

Description

聪聪和可然而兄弟俩,他们俩时时为了局部麻烦事打起来,例如家庭只剩下最后一根冰棍而三人都想吃、两人都想玩儿电脑(不过他们家只有一台总计机)……碰到这种问题,一般情状下石头剪刀布就好了,不过他们一度玩儿腻了这种低智商的嬉戏。他们的老爹快被她们的扯皮烦死了,所以她表明了一个新游戏:由三叔在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),假使两个点期间具有边上数的和加起来刚刚是3的翻番,则判聪聪赢,否则可可赢。聪聪相当爱思考问题,在每一趟游戏后都会细心探讨这棵树,希望知晓对于这张图自己的制胜概率是有点。现请你帮助求出这多少个值以证实聪聪的答案是否正确。

大帮会的帮规比高校校规还多

绝大多数PVP(player vs player
指玩家对阵)玩家都梦想能进来阵营排行靠前的大帮会,不仅利于好、物资多,仍能成为阵营攻防战的主力军。

当其他小帮会还在围点打援时,你曾经得以跟着攻防指挥深远一线战场,绑伊始雷直接炸掉敌方箭塔并攻占据点了,想想都很燃很刺激。

可是 PVP 大帮会对成员的要求也是出了名的从严:

每一天按时签到;

上游戏必挂 YY,YY 名字务必比照帮会规定改;

帮会活动必须参加,特殊情状要向管理提前请假;

攻防期间严禁挂机、严禁打副本和比赛场;

帮友被敌对战营埋复活点的时候必须随叫随到……

本身自然以为学校每一日早晨6:50出操,星期三夜晚还要开班会一度很不同房了,直到自己看齐了帮会重大活动一览表。

自从上了高等高校,我课表都没排这么满过

学员党表示,自从开头渣剑三,帮会上线签到率和各大活动插手率已经秒杀所有学期的上课出勤率了。

对于上班族来说,玩个游戏有时候比工作都累,上班趁首席执行官不在时还是可以开拓微信和Taobao摸个鱼。

唯独在剑三攻防战期间,上个厕所喝口水重返都能接过帮会管理的一些条私聊:

“别以为你在队尾挂机蹭分我不了解!我看你蓝条半分钟都没动过,你是不是对抗性帮派来的艺人!”

有意中人抱怨说:

“我们帮规一共16条,每条下边还有5个以上的小点,重点都用五彩标记,个别还有备注。不吹不黑,写帮规这群戏精高三假使能这样记笔记,估算各种都能上武大。”

“在一连两回忘记参预帮会活动被帮主点名批斗后,我算是给协调设置了手机提醒。”

“我们帮会规定,挂小房间打比赛场不准上锁,一度让别人觉得我们帮是在严俊打击裸聊和传销……”

Output

 对于幽香的每个操作,输出操作完成之后,每一天的小不点儿花费,也即假设幽香选取最优的补给点举行补给时的花费。 

贴吧成了戏精的高产地

就算您能在帮里发现部分奇葩:

一连担心被夺皇位、满脸都写着膨胀的帮主,帮主总有那么多少个戏精徒弟,帮主夫人总是会遭受各路黄茶和白莲小三。

只是逛过剑网三贴吧的人都掌握,这里才是生产戏精和818(八卦和吐槽)的主阵地。

吧里不定时表演各类狗血大戏,其“美观”程度不亚于实际版的原配打小三,徒手撕渣男。

最知名的吐槽帖要数《818分外重病不治坚持不渝剑三的帮主夫人唷》。

故事的女主角集公主病、戏精、被害妄想症于寥寥,平常在帮主指挥团本的时候
YY
插话,一口一个“相姑丈~”叫得人鸡皮疙瘩掉一地,并以为每一个跟帮主搭话的胞妹都是不怀好意想上位的小三。

要是“帮主夫人”的故事让你体会到女子作起来能怎么的惊天地泣鬼神,那么在《怀孕四个月的女对象还不及撩七天的小三》这篇818里,男主跟女主游戏奔现,女主怀孕后男主在打闹里出轨另一个妹子,并直接导致女主不孕症。

女主找人发帖声讨渣男,网友扒出渣男资料,竟发现男主已婚,于是上演了一出原配变小三、小三变小四的惊天大逆袭,堪称年度一级狗血大戏。

传言当事人在线对(si)质(bi)当晚,YY
围观人数突破12万,阵营党们无心干架,连攻防指挥都摈弃据点来听818了。

各大敌对帮会齐聚同一YY频道, 难得地没有撕逼而是百般调匀地联合骂渣男   

无怪乎有人慨叹:“ ‘剑侠’、‘情缘’和‘三’是其一游乐的二种玩法。”

都说剑三真江湖,策马仗剑、肆意而战的江湖即使令人向往,吃瓜吐槽、智斗戏精的人间想想也别有一番乐趣。

HINT

对于100%的数据, N ≤100000, M ≤500000。

 

 那么大家看这一个题,假诺那些题不用修改的话,$O(n)$的树规和$O(nlogn)$的点分治都得以缓解。

想转手,我们需要什么样变量呢?需要最长链和次长链拼起来对啊……

那么我们得以用部分数据结构维护每个点在分治树中伸下去与子树中的每个黑点之间链的长短,

其一数据结构我们可以用大根堆,那么最长链就是堆顶了。

但与此同时,大家发现到最长链和次长链不可以来自同一棵分治树下的子树,

就此我们再来一个数据结构,维护那多少个点每个分治树外甥的堆顶(这就是分治树中“维护二伯/维护孩子”思想的反映,即使不是很醒目),大家仍能够用个堆。

这就是说这多少个堆的前几个元素之和就是透过那多少个点的最长链长度,我们对此每个点都得以保障这么一个变量(当然,也说不定不设有)。

这就是说我们再用一个大根堆维护每个节点的答案,那么这么些堆的堆顶就是答案了。

老是修改的时候,大家在首先类堆中删去或者添加对应的链长,维护第二类堆对应子树的元素,再革新第三类堆中的答案,就落实了五次维护。

分治树的吃水是$logn$的,堆操作的是$logn$的,因而时间复杂度为$O(nlog^{2}n)$。

代码实现:

图片 5图片 6

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <ctime>
  4 #include <set>
  5 #include <queue>
  6 using namespace std;
  7 #define N 100010
  8 #define inf 0x3fffffff
  9 #define Vt Vater[rt]
 10 int n,e,adj[N];
 11 struct edge{int zhong,next;}s[N<<1];
 12 inline void add(int qi,int zhong)
 13     {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
 14 int Vater[N],size[N],root,totsize,maxs[N];
 15 bool state[N],vis[N];
 16 #define max(a,b) ((a)>(b)?(a):(b))
 17 #define min(a,b) ((a)<(b)?(a):(b))
 18 struct heap
 19 {
 20     priority_queue<int>q1,q2;
 21     inline void push(int x){q1.push(x);}
 22     inline void erase(int x){q2.push(x);}
 23     inline int top()
 24     {
 25         while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();
 26         return q1.top();
 27     }
 28     inline void pop()
 29     {
 30         while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();
 31         q1.pop();
 32     }
 33     inline int top2()
 34     {
 35         int val=top();pop();
 36         int ret=top();push(val);
 37         return ret;
 38     }
 39     inline int size()
 40     {
 41         return q1.size()-q2.size();
 42     }
 43 }h1[N],h2[N],h3;
 44 inline void dfs1(int rt,int fa)
 45 {
 46     size[rt]=1,maxs[rt]=0;
 47     for(int i=adj[rt];i;i=s[i].next)
 48         if(s[i].zhong!=fa&&!vis[s[i].zhong])
 49             dfs1(s[i].zhong,rt),size[rt]+=size[s[i].zhong],
 50             maxs[rt]=max(maxs[rt],size[s[i].zhong]);
 51     maxs[rt]=max(maxs[rt],totsize-maxs[rt]);
 52     if(maxs[rt]<maxs[root])root=rt;
 53 }
 54 int f[N][18],bin[25],tp,deep[N];
 55 inline void pre(int rt,int fa)
 56 {
 57     f[rt][0]=fa;deep[rt]=deep[fa]+1;
 58     for(int i=1;bin[i]+1<=deep[rt];++i)f[rt][i]=f[f[rt][i-1]][i-1];
 59     for(int i=adj[rt];i;i=s[i].next)
 60         if(s[i].zhong!=fa)pre(s[i].zhong,rt);
 61 }
 62 inline int LCA(int a,int b)
 63 {
 64     if(deep[a]<deep[b])a^=b,b^=a,a^=b;
 65     int i,cha=deep[a]-deep[b];
 66     for(i=tp;~i;--i)if(cha&bin[i])a=f[a][i];
 67     if(a==b)return a;
 68     for(i=tp;~i;--i)
 69         if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
 70     return f[a][0];
 71 }
 72 inline int dis(int a,int b)
 73     {return deep[a]+deep[b]-(deep[LCA(a,b)]<<1);}
 74 inline void dfs3(int rt,int fa,int Vatty)
 75 {
 76     h1[root].push(dis(rt,Vatty));
 77     for(int i=adj[rt];i;i=s[i].next)
 78         if(!vis[s[i].zhong]&&s[i].zhong!=fa)
 79             dfs3(s[i].zhong,rt,Vatty);
 80 }
 81 inline void dfs2(int rt,int fa)
 82 {
 83     Vt=fa,vis[rt]=1,h2[rt].push(0);
 84     int siz=totsize;
 85     for(int i=adj[rt];i;i=s[i].next)
 86         if(!vis[s[i].zhong])
 87         {
 88             if(size[s[i].zhong]>size[rt])
 89                 totsize=siz-size[rt];
 90             else 
 91                 totsize=size[s[i].zhong];
 92             root=0,dfs1(s[i].zhong,0),dfs3(root,0,rt);
 93             h2[rt].push(h1[root].top()),dfs2(root,rt);
 94         }
 95     if(h2[rt].size()>1)h3.push(h2[rt].top()+h2[rt].top2());
 96 }
 97 inline void turnoff(int who)
 98 {
 99     int val,tmp;
100     if(h2[who].size()>1)h3.erase(h2[who].top()+h2[who].top2());
101     h2[who].push(0);
102     if(h2[who].size()>1)h3.push(h2[who].top()+h2[who].top2());
103     //queue empty() 后依然有数
104     for(int rt=who;Vt;rt=Vt)
105     {
106         if(h2[Vt].size()>1)h3.erase(h2[Vt].top()+h2[Vt].top2());
107         if(h1[rt].size())h2[Vt].erase(h1[rt].top());
108         h1[rt].push(dis(who,Vt));
109         h2[Vt].push(h1[rt].top());
110         if(h2[Vt].size()>1)h3.push(h2[Vt].top()+h2[Vt].top2());
111     }
112 }
113 inline void turnon(int who)
114 {
115     int val,tmp;
116     if(h2[who].size()>1)h3.erase(h2[who].top()+h2[who].top2());
117     h2[who].erase(0);
118     if(h2[who].size()>1)h3.push(h2[who].top()+h2[who].top2());
119     //queue empty()后依然有数
120     for(int rt=who;Vt;rt=Vt)
121     {
122         if(h2[Vt].size()>1)h3.erase(h2[Vt].top()+h2[Vt].top2());
123         h2[Vt].erase(h1[rt].top());
124         h1[rt].erase(dis(who,Vt));
125         if(h1[rt].size())h2[Vt].push(h1[rt].top());
126         if(h2[Vt].size()>1)h3.push(h2[Vt].top()+h2[Vt].top2());
127     }
128 }
129 char B[1<<15],X=0,*S=B,*T=B;
130 #define getc ( S==T&&( T=(S=B)+fread(B,1,1<<15,stdin),S==T )?0:*S++ )
131 inline int read()
132 {
133     int x=0;while(X<'0'||X>'9')X=getc;
134     while(X>='0'&&X<='9')x=10*x+(X^48),X=getc;
135     return x;
136 }
137 inline void readc(){X=getc;while(X<'A'||X>'Z')X=getc;}
138 int main()
139 {
140     // freopen("hide1.in","r",stdin);
141     // freopen("hide.out","w",stdout);
142     n=read();
143     register int i,j,q,a,b,cnt=n;
144     for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1;
145     while(bin[tp+1]<=n)++tp;
146     for(i=1;i<n;++i)
147         a=read(),b=read(),add(a,b),add(b,a);
148     pre(1,0);
149     maxs[0]=inf,root=0,totsize=n,dfs1(1,0),dfs2(root,0);
150     q=read();
151     while(q--)
152     {
153         readc();
154         if(X=='C')
155         {
156             i=read();
157             if(state[i])++cnt,turnoff(i);
158             else --cnt,turnon(i);
159             state[i]^=1;
160         }
161         else
162         {
163             if(cnt<2)printf("%d\n",cnt-1);
164             else printf("%d\n",h3.top());
165         }
166     }
167 }

BZOJ1095

实则这道题是比较简单的……那么大家再看一道题。

我们都知情,一般大型网游都有儒家 /
公会系统,既能增强玩家之间的交互和关系,也能让玩家在打闹中找到家一般的归属感。

Sample Output

0
1
2
4

Output

  对于每一个操作Game,输出一个非负整数到hide.out,表示最远的五个关灯房间的相距。若唯有一个房间是关
着灯的,输出0;若持有房间的灯都开着,输出-1。

唯独却很难用单独的数组维护对应的音讯,这样我们就有了三磷酸腺苷质点分治。

Sample Output

1603
957
7161
9466
3232
5223
1879
1669
1282
0

Input

 第一行七个用空格分开的数 n、Q和A,表示树的轻重缓急、开店的方案个数和妖

怪的年华上限。 

其次行n个用空格分开的数 x_1、x_2、…、x_n,x_i 表示第i 个地方妖怪的年

龄,满足0<=x_i<A。(年龄是足以为 0的,例如刚出生的妖魔的年纪为
0。) 

接下去 n-1 行,每行六个用空格分开的数 a、b、c,表示树上的顶峰 a 和 b 之

间有一条权为c(1 <= c <= 1000)的边,a和b 是终端编号。 

接下去Q行,每行五个用空格分开的数 u、 a、 b。对于这 Q行的每一行,用 a、

b、A总结出 L和R,表示了然“在地点 u开店,面向妖怪的年龄区间为[L,R]的方

案的方便值是稍微”。对于其中第 1 行,L 和 R
的总结办法为:L=min(a%A,b%A), 

R=max(a%A,b%A)。对于第 2到第 Q行,倘诺前一行得到的方便值为 ans,那么当

腾飞的 L 和 R 总括办法为: L=min((a+ans)%A,(b+ans)%A), 

R=max((a+ans)%A,(b+ans)%A)。 

 

Sample Input

10 5
1 2 1
2 3 1
2 4 1
1 5 1
2 61
2 7 1
5 8 1
7 91
1 10 1
3 1
2 1
8 1
3 1
4 1

Input

共有 n + 2 行。 
先是行包含一个正整数,表示测试点编号。 
其次行包含一个正整数 n ,表示总共要参预的节点数。 
我们令参预节点前的累计朋友对数是 last_ans,在一最先时它的值为0。 
接下去 n 行中第 i 行有三个数 ai, bi, ri,表示节点  i  的父节点的数码为
ai xor (last_ans mod 10^9)   (其中xor 表示异或,mod 
表示取余,数据保证这样操作后取得的结果介于 1到i  – 
1之间),与父节点之间的边权为 ci,节点 i 上小精灵的感想力量值为r!。 
小心 a1 = c1 = 0,表示 1 号点是根节点,对于 i >
1,父节点的号子至少为1。

一.树规到点分治

Output

以即约分数情势出口这一个概率(即“a/b”的款式,其中a和b必须互质。假如概率为1,输出“1/1”)。

我们可以总计此前糟糕总结的东西

Description

强强和萌萌是一对好情人。有一天他们在外界闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的快慢从紫荆树上长了出来。仔细看看的话,这多少个大树实际上是一个带权树。每个时刻它会长出一个新的纸牌节点。每个节点上有一个迷人的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌然而也很薄弱的海洋生物,每个小精灵
i 都有一个感触力量值Ri ,小精灵 i, j 成为恋人当且仅当在树上 i 和 j
的偏离 dist(i,j) ≤ Ri + R! ,其中 dist(i, j)表示在这么些树上从 i 到 j
的绝无仅有路径上有着边的边权和。强强和萌萌很愕然每一回新长出一个纸牌节点之后,这个树上总共有几对朋友。  
俺们假设那一个树一开首为空,节点按照进入的逐一从
1起初编号。由于强强非常讶异,
你不能够不在他老是出现新节点后当即给出总共的情人对数,不可以拖延哦。 

2152: 聪聪可可

Time Limit: 3 Sec  Memory
Limit: 259 MB

2599: [IOI2011]Race 

Time Limit: 70 Sec  Memory
Limit: 128 MB

Description给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N
<= 200000, K <= 1000000

Input第一行 两个整数 n, k第二..n行 每行四个整数
表示一条无向边的双边和权值 (注意点的号子从0开首)

Output一个平头 表示很小边数量 假使不存在这样的路线 输出-1

Sample Input

4 3

0 1 1

1 2 2

1 3 4

Sample Output

2

总的来看这道题,原本树规的做法分明行不通了:

假若我们定义$f[i][j]$为以i为根的子树中长度为j的门路最小边数,空间和岁月复杂度都会爆炸。

其一时候大家再思考刚才点分治的做法:

咱俩仅用一个数组$f[j]$表示到每个重点之后子树中长度为j的门径最小边数,

下一场到各样大旨之后通过dfs遍历去改进对应的f值,然后再用f数组之间相加==k的元素之和立异答案。

诸如此类,我们就用一个$log$的代价,解决了树规解决很辛劳的题材。时间复杂度$O(nlogn)$.

代码: 

图片 7图片 8

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 #define N 200010
 5 #define K 1000010
 6 #define LL long long
 7 #define max(a,b) ((a)>(b)?(a):(b))
 8 #define min(a,b) ((a)<(b)?(a):(b))
 9 int n,k,e,adj[N],ans,cnt[K];
10 bool vis[N];
11 int root,tot,size[N],maxs[N];
12 LL dis[N];
13 struct edge{int zhong,val,next;}s[N<<1];
14 inline void add(int qi,int zhong,int val)
15     {s[++e].zhong=zhong;s[e].val=val;s[e].next=adj[qi];adj[qi]=e;}
16 inline void dfs1(int rt,int fa)
17 {
18     size[rt]=1,maxs[rt]=0;
19     for(int i=adj[rt];i;i=s[i].next)
20         if(!vis[s[i].zhong]&&s[i].zhong!=fa)
21             dfs1(s[i].zhong,rt),size[rt]+=size[s[i].zhong],maxs[rt]=max(maxs[rt],size[s[i].zhong]);
22     maxs[rt]=max(maxs[rt],tot-size[rt]);
23     if(maxs[rt]<maxs[root])root=rt;
24 }
25 inline void dfs2(int rt,int fa,int deep)
26 {
27     if(dis[rt]>=0&&dis[rt]<=k)ans=min(ans,deep+cnt[k-dis[rt]]);
28     for(int i=adj[rt];i;i=s[i].next)
29         if(!vis[s[i].zhong]&&s[i].zhong!=fa)
30             dis[s[i].zhong]=dis[rt]+s[i].val,dfs2(s[i].zhong,rt,deep+1);
31 }
32 inline void update(int rt,int fa,int deep,bool opt)
33 {
34     if(dis[rt]>=0&&dis[rt]<=k)
35         if(opt)cnt[dis[rt]]=min(cnt[dis[rt]],deep);
36         else cnt[dis[rt]]=n;
37     for(int i=adj[rt];i;i=s[i].next)
38         if(!vis[s[i].zhong]&&s[i].zhong!=fa)
39             update(s[i].zhong,rt,deep+1,opt);
40 }
41 inline void solve(int rt)
42 {
43     vis[rt]=1;cnt[0]=0;
44     for(int i=adj[rt];i;i=s[i].next)
45         if(!vis[s[i].zhong])
46             dis[s[i].zhong]=s[i].val,dfs2(s[i].zhong,0,1),update(s[i].zhong,0,1,1);
47     for(int i=adj[rt];i;i=s[i].next)
48         if(!vis[s[i].zhong])
49             update(s[i].zhong,0,1,0);
50     for(int i=adj[rt];i;i=s[i].next)
51         if(!vis[s[i].zhong])
52             root=0,tot=size[s[i].zhong],dfs1(s[i].zhong,0),solve(root);
53 }
54 int main()
55 {
56     // freopen("Ark.in","r",stdin);
57     register int i,a,b,c;scanf("%d%d",&n,&k),ans=n;
58     for(i=1;i<n;++i)scanf("%d%d%d",&a,&b,&c),++a,++b,add(a,b,c),add(b,a,c);
59     for(i=1;i<=k;++i)cnt[i]=n;
60     root=0,maxs[0]=n,tot=n,dfs1(1,0),solve(root),
61     printf("%d\n",(ans==n)?-1:ans);
62 }

BZOJ2599

点分治最基本的思索就是这么,找到重心,分别统计。其他的练习还有:

bzoj4016
(建最短路树,再点分)

图片 9图片 10

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 #define N 30010
 7 #define inf 0x3fffffff
 8 #define max(a,b) ((a)>(b)?(a):(b))
 9 int n,m,k,e,adj[N],q[N<<4],hd,tl;bool vis[N];
10 struct edge{int to,next,val;}s[N<<1];
11 inline void add(int qi,int to,int val)
12     {s[++e].to=to;s[e].next=adj[qi];adj[qi]=e;s[e].val=val;}
13 int totsize,root,size[N],maxs[N],maxl[N],cnt[N],dis[N],ans=-inf,tot;
14 struct node{int to,val;};vector<node>to[N];
15 inline bool mt(const node &a,const node &b){return a.to<b.to;}
16 inline void dfs0(int rt)
17 {
18     vis[rt]=1;
19     for(int i=0,l=to[rt].size();i<l;++i)
20         if(!vis[to[rt][i].to]&&dis[to[rt][i].to]==dis[rt]+to[rt][i].val)
21             add(rt,to[rt][i].to,to[rt][i].val),add(to[rt][i].to,rt,to[rt][i].val),dfs0(to[rt][i].to);
22 }
23 inline void spfa_and_build()
24 {
25     memset(dis,0x3f,sizeof(dis));
26     q[hd=tl=1]=1,vis[1]=1,dis[1]=0;
27     register int i,x,l;
28     while(hd<=tl)
29         for(x=q[hd++],vis[x]=0,i=0,l=to[x].size();i<l;++i)
30             if(dis[to[x][i].to]>dis[x]+to[x][i].val)
31             {
32                 dis[to[x][i].to]=dis[x]+to[x][i].val;
33                 if(!vis[to[x][i].to])vis[to[x][i].to]=1,q[++tl]=to[x][i].to;
34             }
35     dfs0(1);
36 }
37 inline void dfs1(int rt,int fa)
38 {
39     size[rt]=1,maxs[rt]=0;
40     for(int i=adj[rt];i;i=s[i].next)
41         if(!vis[s[i].to]&&s[i].to!=fa)
42             dfs1(s[i].to,rt),size[rt]+=size[s[i].to],maxs[rt]=max(maxs[rt],size[s[i].to]);
43     maxs[rt]=max(maxs[rt],totsize-size[rt]);
44     if(maxs[rt]<maxs[root])root=rt;
45 }
46 inline void dfs2(int rt,int fa,int dp)
47 {
48     if(maxl[k-dp-1]!=-inf)
49         if(ans<dis[rt]+maxl[k-dp-1])ans=dis[rt]+maxl[k-dp-1],tot=cnt[k-dp-1];
50         else if(ans==dis[rt]+maxl[k-dp-1])tot+=cnt[k-dp-1];
51     if(dp+1<k)for(int i=adj[rt];i;i=s[i].next)
52         if(!vis[s[i].to]&&s[i].to!=fa)
53             dis[s[i].to]=dis[rt]+s[i].val,dfs2(s[i].to,rt,dp+1);
54 }
55 inline void update(int rt,int fa,int dp)
56 {
57     if(maxl[dp]<dis[rt])maxl[dp]=dis[rt],cnt[dp]=1;
58     else if(maxl[dp]==dis[rt])++cnt[dp];
59     if(dp+1<k)for(int i=adj[rt];i;i=s[i].next)
60         if(!vis[s[i].to]&&s[i].to!=fa)
61             update(s[i].to,rt,dp+1);
62 }
63 inline void solve(int rt)
64 {
65     vis[rt]=1,maxl[0]=0,cnt[0]=1;
66     for(int i=adj[rt];i;i=s[i].next)
67         if(!vis[s[i].to])dis[s[i].to]=s[i].val,dfs2(s[i].to,0,1),update(s[i].to,0,1);
68     for(int i=1;i<=k;++i)maxl[i]=-inf,cnt[i]=0;
69     // for(int i=adj[rt];i;i=s[i].next)if(!vis[s[i].to])update(s[i].to,0,1,0);
70     for(int i=adj[rt];i;i=s[i].next)
71         if(!vis[s[i].to]&&size[s[i].to]>=k)root=0,totsize=size[s[i].to],dfs1(s[i].to,0),solve(root);
72 }
73 inline void work_and_print()
74 {
75     memset(vis,0,sizeof(vis)),memset(dis,0,sizeof(dis)),memset(cnt,0,sizeof(cnt));
76     for(int i=1;i<=k;++i)maxl[i]=-inf;
77     totsize=n,root=0,maxs[0]=inf,dfs1(1,0),solve(root);
78     printf("%d %d",ans,tot);
79 }
80 int main()
81 {
82     scanf("%d%d%d",&n,&m,&k);
83     register int i,j,l,a,b,c;
84     for(i=1;i<=m;++i)
85         scanf("%d%d%d",&a,&b,&c),to[a].push_back((node){b,c}),to[b].push_back((node){a,c});
86     for(i=1;i<=n;++i)sort(to[i].begin(),to[i].end(),mt);
87     spfa_and_build(),work_and_print();
88 }

BZOJ4016

bzoj3672
(推式子,点分治+CDQ维护凸壳)

bzoj1758
(01分数规划,卡精卡时……)

二.从点分治到动态点分治

做着做着题,你恐怕会发现一些题目要修改……这可如何是好呢。

大家肯定不可以几回修改跑一遍DP或者点分治啊……

这就是说大家考虑用数组或者数据结构来保障我们需要的音信,每一遍修改都维护数据结构中对应的消息。
这实质上借用了树规中的思想,我们透过体贴这个消息,可以兑现点之间$O(1)$或者$O(logn)$的更换。

但是假诺我们对原树中的点维护这个数据结构,一条链就足以送我们上天……

但还要我们着眼到,倘诺我们把点分治时每一层的关键性之间连边,这就结成了一颗中度为$logn$的新树,我们叫它分治树。

这就是说大家就用数据结构维护分治树种对应我们需要的音信。

一个常用的思索:维护当前子树中到三叔的某些音信,从而减小查询的复杂度……

如此说可能有点不着边际……大家来看道题:

1095: [ZJOI2007]Hide 捉迷藏

Time Limit: 40 Sec  Memory Limit: 256 MB

Output

对于每个方案,输出一行表示方便值。 

 

HINT

1<=Ci<=10000
Ai<=2*10^9
Ri<=10^9
N<=100000

 

那么那题怎么办啊……

我们先考虑把题设式子变形:

\[dis(u,v)<=r_{u}+r_{v}
 \]

\[dis(u,lca)+dis(lca,v)<=r_{u}+r_{v}
 \]

\[r_{u}-dis(lca,u)>=dis(lca,v)-r_{v}\]

那么接下去大家沿用上边几题的牵挂,在原树上每个节点开2棵平衡树,维护以i为根的子树中的$dis(i,u)-r_{u}$值和$dis(fa[i],u)-r_{u}$值。

如此这般每回我们从新插入的节点伊始往上爬到根,并且更新答案即可。

而是我们发现,假设这是条链……时间复杂度会被卡到$O(n^{2})$

可是大家转念一想,点分树是相对平衡的,深度是$logn$级其它哟!

从而咱们借用替罪羊拍扁重建的思索,如果在插入截至后,

某个节点的某个外外甥特地大(用$alpha$判断),大家就把这棵子树重构为一棵分治树。

这么大家的复杂度可以有$O(nlog^{2}n)$的维持。

在代码实现的时候,要特别注意重构时和原先那多少个子树的分治树五伯之间信息的掩护。

代码:

图片 11图片 12

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <vector>
  5 using namespace std;
  6 #define LL long long
  7 #define inf 1000000000
  8 #define N 100010
  9 #define alpha 0.755
 10 int n,e,adj[N],val[N];
 11 struct edge{int zhong,next;}s[N<<1];
 12 inline void add(int qi,int zhong)
 13     {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
 14 vector<int> to[N];
 15 int f[N][18],bin[25],tp,deep[N],len[N];
 16 inline int LCA(int a,int b)
 17 {
 18     if(deep[a]<deep[b])a^=b,b^=a,a^=b;
 19     int i,cha=deep[a]-deep[b];
 20     for(i=tp;~i;--i)if(cha&bin[i])a=f[a][i];
 21     if(a==b)return a;
 22     for(i=tp;~i;--i)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
 23     return f[a][0];
 24 }
 25 inline int dis(int a,int b){return len[a]+len[b]-len[LCA(a,b)]*2;}
 26 struct Goat
 27 {
 28     int val,size;Goat *ch[2];
 29     Goat(){}
 30     inline bool bad()
 31         {return ch[0]->size>=size*alpha+5 || ch[1]->size>=size*alpha+5; }
 32 }*tree1[N],*tree2[N],mem[N<<8],*pool[N<<8],*null,*sta[N];
 33 int tot,top;
 34 inline void intn()
 35 {
 36     null=new Goat();
 37     null->ch[0]=null->ch[1]=null,null->val=null->size=0;
 38     for(int i=0;i<(N<<8);++i)pool[i]=mem+i;
 39     tot=(N<<8)-1;
 40     for(int i=0;i<=n;++i)tree1[i]=tree2[i]=null;
 41 }
 42 inline Goat** insert(Goat *&a,int val)
 43 {
 44     if(a==null)
 45     {
 46         a=pool[tot--],a->ch[0]=a->ch[1]=null;
 47         a->val=val,a->size=1;return &null;
 48     }
 49     ++a->size;
 50     Goat **o=insert(a->ch[a->val<val],val);
 51     if(a->bad())o=&a;return o;
 52 }
 53 inline int get_rank(Goat *o,int val)
 54 {
 55     if(o==null)return 0;
 56     return (o->val>=val)?get_rank(o->ch[0],val):(get_rank(o->ch[1],val)+o->ch[0]->size+1);
 57 }
 58 inline void Erholung(Goat *o)
 59 {
 60     if(o==null)return;
 61     if(o->ch[0]!=null)Erholung(o->ch[0]);
 62     pool[++tot]=o;
 63     if(o->ch[1]!=null)Erholung(o->ch[1]);
 64 }
 65 inline void travel(Goat *o)
 66 {
 67     if(o==null)return;
 68     if(o->ch[0]!=null)travel(o->ch[0]);
 69     sta[++top]=o;
 70     if(o->ch[1]!=null)travel(o->ch[1]);
 71 }
 72 inline Goat* build(int l,int r)
 73 {
 74     if(l>r)return null;
 75     int mi=l+r>>1;
 76     Goat *o=sta[mi];o->size=r-l+1;
 77     o->ch[0]=build(l,mi-1),o->ch[1]=build(mi+1,r);
 78     return o;
 79 }
 80 inline void rebuild(Goat *&o){top=0,travel(o),o=build(1,top);}
 81 inline void Insert(Goat *&a,int val)
 82 {
 83     Goat **o=insert(a,val);
 84     if(*o!=null)rebuild(*o);
 85 }
 86 int size[N],maxs[N],totsize,root,Vater[N];
 87 #define max(a,b) ((a)>(b)?(a):(b))
 88 #define min(a,b) ((a)<(b)?(a):(b))
 89 bool vis[N];
 90 inline void dfs1(int rt,int fa)
 91 {
 92     size[rt]=1,maxs[rt]=0;
 93     for(int i=adj[rt];i;i=s[i].next)
 94         if(!vis[s[i].zhong]&&s[i].zhong!=fa)
 95             dfs1(s[i].zhong,rt),size[rt]+=size[s[i].zhong],
 96             maxs[rt]=max(maxs[rt],size[s[i].zhong]);
 97     maxs[rt]=max(maxs[rt],totsize-size[rt]);
 98     if(maxs[rt]<maxs[root])root=rt;
 99 }
100 inline void dfs2(int rt,int fa,int Vatti)
101 {
102     Insert(tree1[Vatti],dis(rt,Vatti)-val[rt]);
103     if(Vater[Vatti])Insert(tree2[Vatti],dis(rt,Vater[Vatti])-val[rt]);
104     for(int i=adj[rt];i;i=s[i].next)
105         if(s[i].zhong!=fa&&!vis[s[i].zhong])
106             dfs2(s[i].zhong,rt,Vatti);
107 }
108 inline void dfs3(int rt,int fa)
109 {
110     Vater[rt]=fa,vis[rt]=1;
111     int siz=totsize;
112     dfs2(rt,0,rt);
113     for(int i=adj[rt];i;i=s[i].next)
114         if(!vis[s[i].zhong])
115         {
116             if(size[s[i].zhong]>size[rt])totsize=siz-size[rt];
117             else totsize=size[s[i].zhong];
118             root=0,dfs1(s[i].zhong,rt),
119             to[rt].push_back(root),dfs3(root,rt);
120         }
121 }
122 inline void recover(int x)
123 {
124     ++totsize,vis[x]=0,
125     Erholung(tree1[x]),Erholung(tree2[x]),
126     tree1[x]=tree2[x]=null;
127     for(int i=0,k=to[x].size();i<k;++i)recover(to[x][i]);
128     to[x].clear();
129 }
130 inline void rebuild(int x)
131 {
132     totsize=0,recover(x),root=0,dfs1(x,0);
133     if(Vater[x])for(int i=0,j=to[Vater[x]].size();i<j;++i)
134         if(to[Vater[x]][i]==x)to[Vater[x]][i]=root;
135     dfs3(root,Vater[x]);
136 }
137 LL ans=0;
138 inline int insert(int x)
139 {
140     int rt,ds,ret=0;
141     for(rt=x;Vater[rt];rt=Vater[rt])
142         ds=val[x]-dis(x,Vater[rt])+1,ans+=get_rank(tree1[Vater[rt]],ds)-get_rank(tree2[rt],ds);
143     for(rt=x;rt;rt=Vater[rt])
144     {
145         Insert(tree1[rt],dis(x,rt)-val[x]);
146         if(Vater[rt])Insert(tree2[rt],dis(x,Vater[rt])-val[x]);
147     }
148     for(rt=x;Vater[rt];rt=Vater[rt])
149         if(tree1[rt]->size>=tree1[Vater[rt]]->size*alpha+5)ret=Vater[rt];//*****
150     return ret;
151 }b 
152 char B[1<<15],*S=B,*T=B;
153 #define getc (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
154 inline int read()
155 {
156     int x=0;register char c=getc;
157     while(c<'0'||c>'9')c=getc;
158     while(c>='0'&&c<='9')x=10*x+(c^48),c=getc;
159     return x;
160 }
161 int main()
162 {
163     n=read(),n=read();
164     register int i,j,x,b;
165     for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1;
166     while(bin[tp+1]<=n)++tp;
167     maxs[0]=inf,root=0,intn();
168     for(i=1;i<=n;++i)
169     {
170         Vater[i]=f[i][0]=read()^(ans%inf),b=read(),val[i]=read();
171         deep[i]=deep[f[i][0]]+1,len[i]=len[f[i][0]]+b;vis[i]=1;
172         if(Vater[i])to[Vater[i]].push_back(i),add(f[i][0],i),add(i,f[i][0]);
173         for(int j=1;bin[j]+1<=deep[i];++j)f[i][j]=f[f[i][j-1]][j-1];
174         x=insert(i);if(x)rebuild(x);
175         printf("%lld\n",ans);
176     }
177 }

BZOJ3435

三.总结

点分治和动态树分治其实是对树规思想的变形。我们运用分治树低度很小的助益,对每个点维护相应的消息,

由此$O(logn)$的额外复杂度来开展普通树规无法形成的操作。希望本文能对您有帮助!

3924: [Zjoi2015]幻想乡战略性游戏

Time Limit: 100 Sec  Memory Limit: 256 MB

Description

 风见幽香有一个好对象叫八云紫,她们时常一起看个别看月亮从诗词歌赋谈到

人生艺术学。近日他们灵机一动,打算在幻想乡开一家小店来做事情赚点钱。这样的

想方设法自然卓殊好啊,不过他们也意识他们面临着一个题材,这就是店开在何地,面

向哪些的人流。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n

个地点,编号为 1 到 n,被 n-1
条带权的边连接起来。每个地点都住着一个怪物,

内部第 i 个地点的怪物年龄是
x_i。妖怪都是些相比较欣赏安静的钱物,所以它们并

不期望和成千上万怪物相邻。所以这么些树所有终端的度数都低于或等于 3。妖怪和人一

样,兴趣点随着年华的更动本来就会变动,比如我们的 18 岁少女幽香和八云紫就

正如欣赏可爱的东西。幽香通过钻探发现,基本上妖怪的兴味只跟年龄有关,所以

菲菲打算挑选一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R
之间(即

年纪大于等于 L、小于等于 R)的怪物的店。也有可能 u这多少个地点离这多少个妖怪相比较

远,于是幽香就想要知道所有年龄在 L 到 R 之间的精灵,到点 u
的偏离的和是多

少(妖怪到 u 的偏离是该妖怪所在地点到 u 的门道上的边的权之和)
,幽香把这些

称为这一个开店方案的方便值。幽香她们还没有控制要把店开在哪个地方,八云紫倒是准

备了过多方案,于是幽香想要知道,对于每个方案,方便值是不怎么呢。

 

Input

输入的第1行包含1个正整数n。前边n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,下面的数是w。

Input

率先行六个数n和Q分别表示树的罗列和香气操作的个数,其中点从1到n标号。 

接下去n-1行,每行多少个正整数a,b,c,表示a和b之间有一条边权为c的边。 

接下去Q行,每行三个数u,e,表示幽香在点u上放了e单位个阵容

(虽然e<0,就相当于是幽香在u上减弱了|e|单位个阵容,说白了就是du←du+e)。

多都督证任哪天刻每个点上的军事数量都是非负的。 

1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5

对此持有数据,这个树上所有点的度数都不超越20

N,Q>=1

 

Description

 傲娇少女幽香正在玩一个相当有意思的战略类游戏,本来那些游戏的地形图实际上还不算太大,幽香还是可以管得回复,不过不精晓怎么现在的网游厂商把嬉戏的地图越做越大,以至于幽香一眼根本看不回复,更别说和别人打仗了。 在战斗以前,幽香现在面临一个要命基本的保管问题亟需解决。 整个地图是一个树结构,一共有n块空地,这多少个空地被n-1条带权边连接起来,使得每两个点期间有一条唯一的不二法门将它们连接起来。在打闹中,幽香可能在空地上平添或者减小部分阵容。同时,幽香可以在一个空地上停放一个补给站。 尽管补给站在点u上,并且空地v上有dv个单位的武装部队,那么幽香每日就要花费dv×dist(u,v)的资财来补给这个部队。由于幽香需要补给持有的部队,因而幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的离开(唯一途径的权和)。 因为游戏的确定,幽香只好采纳一个空地作为补给站。在戏耍的历程中,幽香可能会在一些空地上创设一些人马,也可能会裁减某些空地上的枪杆子,举办了那样的操作之后,出于经济上的考虑,幽香往往可以运动她的补给站从而省一些钱。不过出于这么些娱乐的地形图是在太大了,幽香不可以任意的举行最优的布局,你能帮帮他呢? 你可以假如一最先所有空地上都尚未武力。

PDF版试题:JudgeOnline/upload/201708/zjoi2015d1.pdf

这篇博客将会介绍点分治以及动态点分治的概括利用,希望阅读本文的你能享有收获,这就再好可是了。

Sample Output

13/25
【样例表达】
13组点对个别是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3)
(4,4) (5,2) (5,3) (5,5)。

【数据规模】
对于100%的数据,n<=20000。

 

得到本题,一个明明的思路是总结长度为3的翻番的路线个数,再比上总的路径个数即是答案。

这就是说我们发现,3的倍数%3=0(废话……),因而我们得以设$f[i][0/1/2]$为以i为根的子树,向下伸出的门道中长度%3=0/1/2的路径数。

诸如此类大家在每一个点简单的联结一下(注意去掉同一子树的贡献)即可。

如此的做法显明是$O(n)$的对啊……

近年来让大家考虑一个蠢一点的做法:

大家仍旧考虑每个点作为路径顶点时符合条件的点的个数,那么我们可以设想它的各样子树,

数一眨眼中间每个路径的条数,然后合起来对吧。

对此那个节点子树中的节点,大家是化作子问题递归处理的。

那么我们可以把树换个形状……换一个逐项来递归处理

鉴于中央有个属性:到其余点的离开和微小,

这我们得以暴力数一下每种长度0/1/2的门径有些许,再暴力加上,然后对于被那么些主体分割出的几个子树分治递归解决……

这么找重心的复杂度呢?大家最多找$log$次重心就会只剩余一个点,由此复杂度为$O(nlogn)$.(因为每回找到一个重点,新的子树最多是原先子树大小的一半)

这就是说介绍一下大家不可以不的操作:

首先是先导化以及数组定义。我的习惯是这么的:

1 int size[N],maxs[N],totsize,root;
2 bool vis[N];
3 inline void intn()
4 {
5     maxs[0]=inf,root=0,dfs1(1,0),solve(root);
6 }

其中$size[i]$表示最近以i点为根的子树size大小
$maxs[i]$为i点size最大的幼子的size(那些“外甥”能够是i点在有根树中的岳父)

$totsize$为眼前联通块大小
$root$为尾声的着重点
$vis[i]$表示i点是否已经被增选作为主导。vis保证大家可以“截取”出准确的呼应联通块然后是找重心的一些:

 1 inline void dfs1(int rt,int fa)
 2 {
 3     size[rt]=1,maxsize[rt]=0;
 4     for(int i=adj[rt];i;i=s[i].next)
 5         if(s[i].zhong!=fa&&!mark[s[i].zhong])
 6         {
 7             dfs1(s[i].zhong,rt),
 8             size[rt]+=size[s[i].zhong],
 9             maxsize[rt]=max(maxsize[rt],size[s[i].zhong]);
10         }
11     maxsize[rt]=max(maxsize[rt],totsize-maxsize[rt]);
12     if(maxsize[rt]<maxsize[root])root=rt;
13 }

这其实看似一个树规的$O(n)$过程……这样找到最终$root$就是大旨。然后是solve过程:

 1 inline void solve(int rt)
 2 {
 3     vis[rt]=1;
 4   /*
 5     deal with ans
 6   */
 7     for(int i=adj[rt];i;i=s[i].next)
 8         if(!vis[s[i].zhong])
 9             totsize=size[s[i].zhong],root=0,
10             dfs1(s[i].zhong,0),solve(root);
11 }

俺们在每一次确定的主心骨上举办总结,calc函数的情节随题目而变,可是大概是长这么的……本题的完好代码:

图片 13图片 14

 1 #include <cstdio>
 2 #include <cstring>
 3 #define N 20010
 4 #define inf 0x7fffffff
 5 #define max(a,b) ((a)>(b)?(a):(b))
 6 int n,e,adj[N],root,totsize,size[N],maxsize[N];
 7 struct edge{int zhong,val,next;}s[N<<1];
 8 inline void add(int qi,int zhong,int val)
 9     {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;s[e].val=val;}
10 bool mark[N];
11 inline void dfs1(int rt,int fa)
12 {
13     size[rt]=1,maxsize[rt]=0;
14     for(int i=adj[rt];i;i=s[i].next)
15         if(!mark[s[i].zhong]&&s[i].zhong!=fa)
16             dfs1(s[i].zhong,rt),size[rt]+=size[s[i].zhong],
17             maxsize[rt]=max(maxsize[rt],size[s[i].zhong]);
18     maxsize[rt]=max(maxsize[rt],totsize-size[rt]);
19     if(maxsize[rt]<maxsize[root])root=rt;
20 }
21 int cnt[3],dist[N],ans;
22 inline void dfs2(int rt,int fa)
23 {
24     ++cnt[dist[rt]];
25     for(int i=adj[rt];i;i=s[i].next)
26         if(!mark[s[i].zhong]&&s[i].zhong!=fa)
27             dist[s[i].zhong]=(dist[rt]+s[i].val)%3,
28             dfs2(s[i].zhong,rt);
29 }
30 inline int calc(int rt,int stval)
31 {
32     dist[rt]=stval,cnt[0]=cnt[1]=cnt[2]=0,dfs2(rt,0);
33     return cnt[0]*cnt[0]+2*cnt[1]*cnt[2];
34 }
35 inline void solve(int rt)
36 {
37     mark[rt]=1,ans+=calc(rt,0);
38     for(int i=adj[rt];i;i=s[i].next)
39         if(!mark[s[i].zhong])
40             ans-=calc(s[i].zhong,s[i].val),
41             totsize=size[s[i].zhong],root=0,
42             dfs1(s[i].zhong,0),solve(root);
43 }
44 inline int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
45 int main()
46 {
47     scanf("%d",&n);
48     register int i,a,b,c;
49     for(i=1;i<n;++i)
50         scanf("%d%d%d",&a,&b,&c),add(a,b,c%3),add(b,a,c%3);
51     totsize=n,root=0,maxsize[0]=inf;
52     dfs1(1,0),solve(root);
53     int di=n*n,d=gcd(di,ans);
54     printf("%d/%d\n",ans/d,di/d);
55 }

BZOJ2152

当今那一个思路看起来相比较蠢对吗……不过如若换一道题,原本的树规做法就不算了。

我们先来看一道简单的题目……

4012: [HNOI2015]开店

Time Limit: 70 Sec  Memory Limit: 512 MB

Output

含蓄 n 行,每行输出1 个整数, 表示参与第 i 个点之后,树上有几对朋友。

Sample Input

8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G

部分时候,我们会发现这么一类题:它长得很像一个$O(n)$的树规,

由此一直总结($O(nlogn)$)或者加上数据结构(比如树状数组,堆,线段树等等)维护消息($O(nlog^{2}n)$),

(写篇博客认证自己还活着×2)

3435: [Wc2014]紫荆花之恋

Time Limit: 240 Sec  Memory
Limit: 512 MB

Description

  捉迷藏
Jiajia和Wind是一对密切的夫妇,并且他们有成百上千男女。某天,Jiajia、Wind和儿女们决定在家里玩
捉迷藏游戏。他们的家很大且结构很蹊跷,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意六个屋
子都互相可达。游戏是这么举行的,孩子们承受藏匿,Jiajia负责找,而Wind负责控制这N个屋子的灯。在开头的
时候,所有的灯都尚未被打开。每几回,孩子们只会躲藏在没有开灯的房间中,不过为了充实刺激性,孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一遍游戏的复杂性,Jiajia希望知晓或者的最远的两
个子女的距离(即最远的三个关灯房间的距离)。
大家将以如下模式定义每一种操作: C(hange) i 改变第i个房
间的照明情状,若原来打开,则关闭;若原来关闭,则打开。 G(ame)
开首五次游戏,查询最远的四个关灯房间的
距离。

发表评论

电子邮件地址不会被公开。 必填项已用*标注