@KirinBill
2018-01-25T01:40:15.000000Z
字数 38897
阅读 1818
分治
目录
点分治和其它分治一样,都是递归进行的(虽然有非递归写法,但是反人类啊,没学会Orz),我们以处理点的子树为例:
1. 找到的子树的重心;
2. ,函数是计算子树中过的路径的贡献;
3. 遍历未访问过的儿子;
4. 对于每个,,函数这里是计算子树中过但是到时有一段路径是重复的(即不是简单路径)这种路径数,也就是减去重复;
5. 递归,分治计算的子树;
伪代码:
//求重心void get_grt(int u,int fa);//计算int solve(int u,int dis);int treeDC(int u){use[u]=true; //标记已经处理过了int ret=solve(u,0); //计算经过u的路径for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){//减去重复,但距离初值要带上这条边,//这样才能表示路径中v到u这一段不是两条链,而是重叠了ret-=solve(v,ed[i].w);grt=0,sum_sz=sz[v]; //初始化重心,找到子树v的get_grt(v,0);ret+=treeDC(grt); //一定不能写成v,不然T上天!!!}}return ret;}
求重心的代码:
void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}
代码:
#include <cstdio>#include <algorithm>#include <climits>using std::sort;using std::max;const int MAXN=40005;int k;int grt,sum_sz;int he[MAXN];int de[MAXN],sz[MAXN];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}//找到重心void get_grt(int u,int fa){static int max_subT[MAXN]={INT_MAX};sz[u]=1,max_subT[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT[u]=max(max_subT[u],sz[v]);}}//无根树,翻过来的也是子树max_subT[u]=max(max_subT[u],sum_sz-sz[u]);//更新重心if(max_subT[u]<max_subT[grt]) grt=u;}void DFS(int u,int fa,int de){::de[++::de[0]]=de;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa) DFS(v,u,de+ed[i].w);}}inline int solve(int u,int _de){de[0]=0;DFS(u,0,_de);sort(de+1,de+de[0]+1);int l=1,r=de[0];int ret=0;while(l<r){//l和l+1,l+2,...,r构成点对,不是区间长if(de[l]+de[r]<=k) ret+=r-l,++l;else --r;}return ret;}int treeDC(int u){use[u]=true;int ret=solve(u,0);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){//减去重复情况ret-=solve(v,ed[i].w);grt=0,sum_sz=sz[v];get_grt(v,0);ret+=treeDC(grt);}}return ret;}int main(){int n;scanf("%d",&n);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);addE(u,v,w),addE(v,u,w);}scanf("%d",&k);sum_sz=n;get_grt(1,0);printf("%d",treeDC(grt));return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>using std::max;using std::sort;const int MAXN=10005,MAXQ=105;int q,grt,sum_sz;int he[MAXN],de[MAXN],sz[MAXN];int qry[MAXN],ans[MAXQ];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int de){::de[++::de[0]]=de;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa) DFS(v,u,de+ed[i].w);}}bool lt(int a,int b){return a<b;}bool leq(int a,int b){return a<=b;}inline int solve(int k,bool jud(int,int)){int l=1,r=de[0],ret=0;if(k==0) return jud(de[1],k);while(l<r){if(jud(de[l]+de[r],k)) ret+=r-l,++l;else --r;}return ret;}void treeDC(int u){use[u]=true;de[0]=0;DFS(u,0,0);sort(de+1,de+de[0]+1);for(int i=1;i<=q;++i)ans[i]+=solve(qry[i],leq)-solve(qry[i],lt);for(int i=he[u],v,w;i;i=ed[i].nex){v=ed[i].to;if(use[v]) continue;w=ed[i].w;de[0]=0;DFS(v,0,ed[i].w);sort(de+1,de+de[0]+1);for(int j=1;j<=q;++j)ans[j]-=solve(qry[j],leq)-solve(qry[j],lt);grt=0,sum_sz=sz[v];get_grt(v,0);treeDC(grt);}}int main(){int n;scanf("%d%d",&n,&q);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);addE(u,v,w),addE(v,u,w);}for(int i=1;i<=q;++i)scanf("%d",&qry[i]);sum_sz=n;get_grt(1,0);treeDC(grt);for(int i=1;i<=q;++i){if(ans[i]) puts("Yes");else puts("No");}return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>#include <cstring>using std::max;const int MAXN=20005;int grt,sum_sz;int he[MAXN];int sz[MAXN],de[MAXN],de_mod3[3];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline int gcd(int a,int b){int r;while(b){r=a%b;a=b,b=r;}return a;}inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void get_grt(int u,int fa){static int max_subT[MAXN]={INT_MAX};sz[u]=1,max_subT[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT[u]=max(max_subT[u],sz[v]);}}max_subT[u]=max(max_subT[u],sum_sz-sz[u]);if(max_subT[u]<max_subT[grt]) grt=u;}void DFS(int u,int fa,int de){++de_mod3[de%3];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa)DFS(v,u,de+ed[i].w);}}inline int solve(int u,int _de){memset(de_mod3,0,sizeof(de_mod3));DFS(u,0,_de);//两个人选,所以两个端点是两个方案return de_mod3[0]*de_mod3[0]+(de_mod3[1]*de_mod3[2]<<1);}int treeDC(int u){use[u]=true;int ret=solve(u,0);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){ret-=solve(v,ed[i].w);grt=0,sum_sz=sz[v];get_grt(v,0);ret+=treeDC(grt);}}return ret;}int main(){int n;scanf("%d",&n);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);addE(u,v,w),addE(v,u,w);}sum_sz=n;get_grt(1,0);int cnt=treeDC(grt),tot=n*n;int gcd=::gcd(cnt,tot);printf("%d/%d",cnt/gcd,tot/gcd);return 0;}
4.[Codeforces 715C] Digit Tree
题目大意:给你一棵个点的树,每条边上有一个数字(~),给出一个与互质的数,问整棵树上有多少条路径满足从起点走到终点的边上形成的十进制数是的倍数。.
代码:
#include <cstdio>#include <algorithm>#include <climits>using std::max;using std::sort;using std::lower_bound;using std::upper_bound;const int MAXN=100005;int grt,m,sum_sz,tot;int he[MAXN],sz[MAXN];int de[MAXN],up[MAXN],dwn[MAXN];int pow10[MAXN];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}int exgcd(int a,int &x,int b,int &y){if(!b){x=1,y=0;return a;}int ret=exgcd(b,y,a%b,x);y-=a/b*x;return ret;}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int de,int up,int dwn){++tot;::de[tot]=de,::up[tot]=up,::dwn[tot]=dwn;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa)DFS(v,u,de+1,(up+(long long)ed[i].w*pow10[de]%m)%m,((long long)dwn*10%m+ed[i].w)%m);}}//ax=b mod cinline int equiv(int a,int b,int c){int x,y;exgcd(a,x,c,y);return (long long)b*((x%c+c)%c)%c;}inline int cal_sum(int val){return upper_bound(up+1,up+tot+1,val)-lower_bound(up+1,up+tot+1,val);}inline long long solve(int u,int _dis){tot=0;DFS(u,0,(bool)_dis,_dis%m,_dis%m);sort(up+1,up+tot+1);long long ret=0;for(int i=1,up;i<=tot;++i){up=equiv(pow10[de[i]],(-dwn[i]+m)%m,m);ret+=cal_sum(up);}//此时,会多计算一个a=b=0的情况,也就是自己一个点if(_dis==0) --ret;return ret;}long long treeDC(int u){use[u]=true;long long ret=solve(u,0);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){ret-=solve(v,ed[i].w);grt=0,sum_sz=sz[v];get_grt(v,0);ret+=treeDC(grt);}}return ret;}int main(){int n;scanf("%d%d",&n,&m);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);++u,++v;addE(u,v,w),addE(v,u,w);}pow10[0]=1;for(int i=1;i<=n;++i)pow10[i]=(long long)pow10[i-1]*10%m;sum_sz=n;get_grt(1,0);printf("%I64d",treeDC(grt));return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>#include <cmath>using std::max;using std::abs;const int MAXN=100005;int grt,sum_sz,max_dis;int he[MAXN],sz[MAXN];int tmp[2][MAXN<<1];int *have[2]={tmp[0]+MAXN,tmp[1]+MAXN};bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int dis){static int tmp[MAXN<<1];static int *pre=tmp+MAXN;max_dis=max(max_dis,abs(dis));++have[(bool)pre[dis]][dis];++pre[dis];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa) DFS(v,u,dis+ed[i].w);}--pre[dis];}inline long long solve(int u){static int tmp[2][MAXN<<1];static int *sum_have[2]={tmp[0]+MAXN,tmp[1]+MAXN};sum_have[0][0]=1;max_dis=0;long long ret=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(use[v]) continue;DFS(v,0,ed[i].w);//休息站在重心上的ret+=(long long)have[0][0]*(sum_have[0][0]-1);for(int i=-max_dis;i<=max_dis;++i){ret+=(long long)sum_have[1][i]*have[1][-i];ret+=(long long)sum_have[0][i]*have[1][-i];ret+=(long long)sum_have[1][i]*have[0][-i];}for(int i=-max_dis;i<=max_dis;++i){sum_have[0][i]+=have[0][i];sum_have[1][i]+=have[1][i];have[0][i]=have[1][i]=0;}}for(int i=-max_dis;i<=max_dis;++i)sum_have[0][i]=sum_have[1][i]=0;return ret;}long long treeDC(int u){use[u]=true;long long ret=solve(u);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){grt=0,sum_sz=sz[v];get_grt(v,0);ret+=treeDC(grt);}}return ret;}int main(){int n;scanf("%d",&n);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);if(w==0) w=-1;addE(u,v,w),addE(v,u,w);}sum_sz=n;get_grt(1,0);printf("%lld",treeDC(grt));return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>#include <queue>#include <vector>#include <functional>#include <cstring>using std::min;using std::max;using std::priority_queue;using std::vector;using std::greater;const int MAXN=30005,MAXM=60005;int n,k,ecnt;int grt,sum_sz;int ans,tot;int he[MAXN],sz[MAXN],dis[MAXN],pre[MAXN];int maxl[MAXN],cnt[MAXN]={1}; //深度为0的只有当前根这一个,且dis=0bool use[MAXN];struct line{int to,nex,w;}ed[MAXM<<1];struct node{int id,dis;node(int _id=0,int _dis=0):id(_id),dis(_dis){}bool operator >(const node &that)const{return dis>that.dis || (dis==that.dis && id>that.id);}};inline void addE(int u,int v,int w){static int &cnt=ecnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}inline void Dijkstra(){static bool use[MAXN];static priority_queue<node,vector<node>,greater<node> > hp;memset(dis,0x7f,sizeof(dis));dis[1]=0;hp.push(node(1,0));int u;while(hp.size()){u=hp.top().id;hp.pop();if(use[u]) continue;use[u]=true;for(int i=he[u],v,d;i;i=ed[i].nex){v=ed[i].to,d=dis[u]+ed[i].w;if(dis[v]>d){dis[v]=d,pre[v]=u;hp.push(node(v,d));}}}}inline void rebuild(){ecnt=0;memset(he,0,sizeof(he));for(int i=2,w;i<=n;++i){w=dis[i]-dis[pre[i]];addE(pre[i],i,w),addE(i,pre[i],w);}}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS_cal(int u,int fa,int de,int dis){//点数=边数+1...if(de>=k) return;if(cnt[k-(de+1)]){int d=dis+maxl[k-(de+1)];if(d>ans) ans=d,tot=cnt[k-(de+1)];else if(d==ans) tot+=cnt[k-(de+1)];}for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa)DFS_cal(v,u,de+1,dis+ed[i].w);}}void DFS_upd(int u,int fa,int de,int dis){if(de>=k) return; //剪枝if(dis>maxl[de]) maxl[de]=dis,cnt[de]=1;else if(dis==maxl[de]) ++cnt[de];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa)DFS_upd(v,u,de+1,dis+ed[i].w);}}void treeDC(int u){use[u]=true;if(sum_sz<=k) return; //剪枝memset(maxl+1,0,sum_sz<<2);memset(cnt+1,0,sum_sz<<2);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){DFS_cal(v,0,1,ed[i].w);DFS_upd(v,0,1,ed[i].w);}}for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){grt=0,sum_sz=sz[v];get_grt(v,0);treeDC(grt);}}}int main(){int m;scanf("%d%d%d",&n,&m,&k);for(int i=1,u,v,w;i<=m;++i){scanf("%d%d%d",&u,&v,&w);addE(u,v,w),addE(v,u,w);}Dijkstra();rebuild();sum_sz=n;get_grt(1,0);treeDC(grt);printf("%d %d",ans,tot);return 0;}
if(max_subT_sz(u)<max_subT_sz(grt)) grt=u还是会爆栈。。。要改成<=,并不清楚啥原理,可能这就是IOI题吧。。。代码:
#include <cstdio>#include <algorithm>#include <climits>#include <cstring>using std::min;using std::max;const int MAXN=200005,MAXK=1000005,INF=0x3f3f3f3f;int k,grt;int he[MAXN],fa[MAXN],de[MAXN],dis[MAXN];int minl[MAXK];int que[MAXN];int &bak=que[0];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}inline void get_grt(int rt){static int sz[MAXN],max_subT_sz[MAXN]={INT_MAX};bak=0;que[++bak]=rt;for(int frt=1,u;frt<=bak;++frt){u=que[frt];sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(use[v] || v==fa[u]) continue;fa[v]=u;que[++bak]=v;}}grt=0;for(int cur=bak,u,fa;cur;--cur){u=que[cur],fa=::fa[u];max_subT_sz[u]=max(max_subT_sz[u],bak-sz[u]);//玄之又玄...if(max_subT_sz[u]<=max_subT_sz[grt]) grt=u;sz[fa]+=sz[u];max_subT_sz[fa]=max(max_subT_sz[fa],sz[u]);//solve的BFS从grt开始,//与get_grt的顺序不同,//要清一下::fa[u]=0;}}inline void BFS(){for(int frt=bak,u;frt<=bak;++frt){u=que[frt];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(use[v] || v==fa[u]) continue;fa[v]=u;dis[v]=dis[u]+ed[i].w,de[v]=de[u]+1;que[++bak]=v;}}}inline int solve(){bak=0;int ret=INT_MAX;for(int i=he[grt],u,lp;i;i=ed[i].nex){u=ed[i].to;if(use[u]) continue;dis[u]=ed[i].w,de[u]=1;que[++bak]=u,lp=bak;BFS();for(int cur=lp,v;cur<=bak;++cur){v=que[cur];if(dis[v]<=k) ret=min(ret,de[v]+minl[k-dis[v]]);}for(int cur=lp,v;cur<=bak;++cur){v=que[cur];if(dis[v]<=k) minl[dis[v]]=min(minl[dis[v]],de[v]);}}return ret;}int treeDC(int rt){use[rt]=true;int ret=solve();for(int cur=1,u;cur<=bak;++cur){u=que[cur];//原因同上fa[u]=0;//和虚树的类似,//每次只清用到的,//不要想复杂了。。。if(dis[u]<=k) minl[dis[u]]=INF;}for(int i=he[rt],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){get_grt(v);ret=min(ret,treeDC(grt));}}return ret;}int main(){int n;scanf("%d%d",&n,&k);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);++u,++v;addE(u,v,w),addE(v,u,w);}get_grt(1);memset(minl+1,0x3f,sizeof(minl)-4);int ans=treeDC(grt);if(ans>=INF) ans=-1;printf("%d",ans);return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>#include <queue>#include <cmath>#include <cstring>using std::max;using std::priority_queue;const int MAXN=50005;int idx,grt,sum_sz;int he[MAXN],sz[MAXN];int len[MAXN<<4],lp[MAXN<<4],rp[MAXN<<4];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];struct chain{int id,lp,rp,len;chain(int _id=0,int _lp=0,int _rp=0,int _len=0):id(_id),lp(_lp),rp(_rp),len(_len){}bool operator <(const chain &that)const{return len<that.len;}};priority_queue<chain> hp;class SparseTab{private:int c[20][MAXN<<4];public:void init(int a[],int n){for(int i=1;i<=n;++i) c[0][i]=i;for(int i=1,lim=log2(n);i<=lim;++i){for(int j=1;j+(1<<i)-1<=n;++j){if(len[c[i-1][j]]>len[c[i-1][j+(1<<i-1)]])c[i][j]=c[i-1][j];else c[i][j]=c[i-1][j+(1<<i-1)];}}}int qry(int l,int r){if(l>r) return 0;int k=log2(r-l+1);if(len[c[k][l]]>len[c[k][r-(1<<k)+1]])return c[k][l];else return c[k][r-(1<<k)+1];}}st;inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int dis,int rp){len[++idx]=dis;lp[idx]=lp[idx-1],::rp[idx]=rp;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa) DFS(v,u,dis+ed[i].w,rp);}}void treeDC(int u){use[u]=true;len[++idx]=0;lp[idx]=rp[idx]=idx;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]) DFS(v,u,ed[i].w,idx);}for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){grt=0,sum_sz=sz[v];get_grt(v,0);treeDC(grt);}}}int main(){int n,m;scanf("%d%d",&n,&m);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);addE(u,v,w),addE(v,u,w);}sum_sz=n;get_grt(1,0);treeDC(grt);st.init(len,idx);for(int i=1;i<=idx;++i){if(lp[i]>rp[i]) continue;hp.push(chain(i,lp[i],rp[i],len[i]+len[st.qry(lp[i],rp[i])]));}chain now;for(int i=1,id,lp,rp,lmid,rmid,mid;i<=m;++i){now=hp.top();hp.pop();printf("%d\n",now.len);id=now.id,lp=now.lp,rp=now.rp;mid=st.qry(lp,rp);lmid=st.qry(lp,mid-1);if(lmid) hp.push(chain(id,lp,mid-1,len[id]+len[lmid]));rmid=st.qry(mid+1,rp);if(rmid) hp.push(chain(id,mid+1,rp,len[id]+len[rmid]));}return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>#include <cstring>using std::max;using std::sort;const int MAXN=100005;int n,grt,k,sum_sz,cut1,cut2;int he[MAXN],sz[MAXN],de[MAXN],cir[MAXN];bool use[MAXN];struct line{int to,nex;}ed[MAXN<<1];class rev_BIT{private:long long c[MAXN];int lowbit(int x){return x&-x;}public:void add(int r){for(;r;r-=lowbit(r)) ++c[r];}long long qry(int l){//如果需要的剩下的长度非正了,//说明这条链已经满足条件了,//那么另一条链长度随意if(l<=0) l=1;long long ret=0;for(;l<=n;l+=lowbit(l))ret+=c[l];return ret;}}ta;inline void addE(int u,int v){static int cnt=1;ed[++cnt]=(line){v,he[u]};he[u]=cnt;}inline int revE(int i){return i^1;}bool find_cir(int u){static int pre[MAXN];static bool vis[MAXN];vis[u]=true;int fa=pre[u];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(v==fa) continue;if(vis[v]){cut1=i,cut2=revE(i);for(int now=u;now!=pre[v];now=pre[now])cir[++cir[0]]=now;return true;}pre[v]=u;if(find_cir(v)) return true;}return false;}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){if(i==cut1 || i==cut2) continue;v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int de){::de[++::de[0]]=de;for(int i=he[u],v;i;i=ed[i].nex){if(i==cut1 || i==cut2) continue;v=ed[i].to;if(!use[v] && v!=fa) DFS(v,u,de+1);}}inline long long solve(int u,int _de){de[0]=0;DFS(u,0,_de);sort(de+1,de+de[0]+1);int l=1,r=de[0];long long ret=0;while(l<r){if(de[l]+de[r]+1<k) ret+=r-l,++l;else --r;}return ret;}long long treeDC(int u){use[u]=true;long long ret=solve(u,0);for(int i=he[u],v;i;i=ed[i].nex){if(i==cut1 || i==cut2) continue;v=ed[i].to;if(!use[v]){ret-=solve(v,1);grt=0,sum_sz=sz[v];get_grt(v,0);ret+=treeDC(grt);}}return ret;}inline long long cal_cutE(){memset(use,false,sizeof(use));for(int i=1;i<=cir[0];++i)use[cir[i]]=true;long long ret=0;for(int i=1,u;i<=cir[0];++i){u=cir[i];de[0]=0;DFS(u,0,0);for(int j=1;j<=de[0];++j) //绕一圈到cir[cir[0]]ret+=ta.qry(k-(de[j]+(cir[0]-i+1)));//两段中间是cir[1]和cir[cir[0]],通过cut边相接for(int j=1;j<=de[0];++j) //直接到cir[1]ta.add(i+de[j]);}return ret;}int main(){int m;scanf("%d%d%d",&n,&m,&k);for(int i=1,u,v;i<=m;++i){scanf("%d%d",&u,&v);addE(u,v),addE(v,u);}find_cir(1);sum_sz=n;get_grt(1,0);long long ans=((long long)n*(n-1)>>1)-treeDC(grt);if(m==n) ans+=cal_cutE();printf("%lld",ans);return 0;}
vector的树状数组或者动态开点的线段树;代码:
#include <cstdio>#include <algorithm>#include <climits>#include <cmath>#include <cstring>using std::max;using std::swap;const int MAXN=100005;int n,sum_sz,grt;int he[MAXN],val[MAXN],fa[MAXN];int dfn[MAXN<<1],pos[MAXN],de[MAXN];int sz[MAXN];bool use[MAXN];struct line{int to,nex;}ed[MAXN<<1];class SparseTab{private:int c[18][MAXN<<1];public:void init(int a[],int n){memcpy(c[0]+1,a+1,n<<2);for(int i=1,lim=log2(n);i<=lim;++i){for(int j=1;j+(1<<i)-1<=n;++j){if(de[c[i-1][j]]<de[c[i-1][j+(1<<i-1)]])c[i][j]=c[i-1][j];else c[i][j]=c[i-1][j+(1<<i-1)];}}}int LCA(int u,int v){u=pos[u],v=pos[v];if(u>v) swap(u,v);int k=log2(v-u+1);if(de[c[k][u]]<de[c[k][v-(1<<k)+1]])return c[k][u];else return c[k][v-(1<<k)+1];}}st;class segT{private:struct node{int sum;node *ls,*rs;node(){sum=0,ls=rs=NULL;}}*rt;void ist(node *&u,int l,int r,int pos,int val){if(!u) u=new(node);u->sum+=val;if(l==r) return;int mid=l+r>>1;if(pos<=mid) ist(u->ls,l,mid,pos,val);else ist(u->rs,mid+1,r,pos,val);}int qry(node *u,int l,int r,int lp,int rp){if(!u) return 0;if(lp<=l && r<=rp) return u->sum;int mid=l+r>>1,ret=0;if(lp<=mid) ret=qry(u->ls,l,mid,lp,rp);if(rp>mid) ret+=qry(u->rs,mid+1,r,lp,rp);return ret;}public:void ist(int pos,int val){ist(rt,0,n,pos,val);}int qry(int lp,int rp){return qry(rt,0,n,lp,rp);}}plus[MAXN],minus[MAXN];inline void addE(int u,int v){static int cnt;ed[++cnt]=(line){v,he[u]};he[u]=cnt;}void DFS(int u,int fa){de[u]=de[fa]+1;dfn[++dfn[0]]=u;pos[u]=dfn[0];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(v!=fa){DFS(v,u);dfn[++dfn[0]]=u;}}}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void solve(int u,int fa,int de,segT &T){T.ist(de,val[u]);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa)solve(v,u,de+1,T);}}void treeDC(int u){use[u]=true;solve(u,0,0,plus[u]);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){grt=0,sum_sz=sz[v];get_grt(v,0);fa[grt]=u;solve(v,0,1,minus[grt]);treeDC(grt);}}}inline int cal_dis(int u,int v){return de[u]+de[v]-(de[st.LCA(u,v)]<<1);}inline int qry(int u,int k){int ret=plus[u].qry(0,k);for(int now=u,dis;fa[now];now=fa[now]){dis=cal_dis(fa[now],u);if(k<dis) continue;ret+=plus[fa[now]].qry(0,k-dis);ret-=minus[now].qry(0,k-dis);}return ret;}inline void mdf(int u,int val){int dta=val-::val[u];::val[u]=val;plus[u].ist(0,dta);for(int now=u,dis;fa[now];now=fa[now]){dis=cal_dis(fa[now],u);plus[fa[now]].ist(dis,dta);minus[now].ist(dis,dta);}}int main(){int m;scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&val[i]);for(int i=1,u,v;i<n;++i){scanf("%d%d",&u,&v);addE(u,v),addE(v,u);}DFS(1,0);st.init(dfn,dfn[0]);sum_sz=n;get_grt(1,0);treeDC(grt);for(int i=1,opt,x,y,lastans=0;i<=m;++i){scanf("%d%d%d",&opt,&x,&y);x^=lastans,y^=lastans;if(opt==0){lastans=qry(x,y);printf("%d\n",lastans);}else mdf(x,y);}return 0;}
代码:
#include <cstdio>#include <algorithm>#include <cstring>#include <climits>#include <cmath>using std::max;using std::swap;const int MAXN=1e5+5;int n,sum_sz,grt;int he[MAXN],sz[MAXN],fa[MAXN];int de[MAXN],dfn[MAXN<<1],pos[MAXN];bool use[MAXN];struct line{int to,nex;}ed[MAXN<<1];class SparseTab{private:int c[18][MAXN<<1];public:void init(int a[],int n){memcpy(c[0]+1,a+1,n<<2);for(int i=1,lim=log2(n);i<=lim;++i){for(int j=1;j+(1<<i)-1<=n;++j){if(de[c[i-1][j]]<de[c[i-1][j+(1<<i-1)]])c[i][j]=c[i-1][j];else c[i][j]=c[i-1][j+(1<<i-1)];}}}int LCA(int u,int v){u=pos[u],v=pos[v];if(u>v) swap(u,v);int k=log2(v-u+1);if(de[c[k][u]]<de[c[k][v-(1<<k)+1]])return c[k][u];else return c[k][v-(1<<k)+1];}}st;class segT{private:struct node{int sum;node *ls,*rs;node(){sum=0,ls=rs=NULL;}}*rt;void mdf(node *&u,int l,int r,int lp,int rp,int val){if(!u) u=new(node);if(lp<=l && r<=rp){u->sum+=val;return;}int mid=l+r>>1;if(lp<=mid) mdf(u->ls,l,mid,lp,rp,val);if(rp>mid) mdf(u->rs,mid+1,r,lp,rp,val);}int qry(node *u,int l,int r,int pos){if(!u) return 0;if(l==r) return u->sum;int mid=l+r>>1,ret=u->sum;if(pos<=mid) ret+=qry(u->ls,l,mid,pos);else ret+=qry(u->rs,mid+1,r,pos);return ret;}public:void mdf(int lp,int rp,int val){mdf(rt,0,n,lp,rp,val);}int qry(int pos){return qry(rt,0,n,pos);}}plus[MAXN],minus[MAXN];inline void addE(int u,int v){static int cnt;ed[++cnt]=(line){v,he[u]};he[u]=cnt;}void DFS(int u,int fa){de[u]=de[fa]+1;dfn[++dfn[0]]=u;pos[u]=dfn[0];for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(v!=fa){DFS(v,u);dfn[++dfn[0]]=u;}}}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void treeDC(int u){use[u]=true;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){grt=0,sum_sz=sz[v];get_grt(v,0);fa[grt]=u;treeDC(grt);}}}inline int cal_dis(int u,int v){return de[u]+de[v]-(de[st.LCA(u,v)]<<1);}inline int qry(int u){int ret=plus[u].qry(0);for(int now=u,dis;fa[now];now=fa[now]){dis=cal_dis(fa[now],u);ret+=plus[fa[now]].qry(dis);ret-=minus[now].qry(dis);}return ret;}inline void mdf(int u,int k,int w){plus[u].mdf(0,k,w);for(int now=u,dis;fa[now];now=fa[now]){dis=cal_dis(fa[now],u);if(dis>k) continue;plus[fa[now]].mdf(0,k-dis,w);minus[now].mdf(0,k-dis,w);}}int main(){int m;scanf("%d%d",&n,&m);for(int i=1,u,v;i<n;++i){scanf("%d%d",&u,&v);addE(u,v),addE(v,u);}DFS(1,0);st.init(dfn,dfn[0]);sum_sz=n;get_grt(1,0);treeDC(grt);char opt;for(int i=1,x,d,w;i<=m;++i){scanf("\n%c%d",&opt,&x);if(opt=='Q') printf("%d\n",qry(x));else{scanf("%d%d",&d,&w);mdf(x,d,w);}}return 0;}
代码:
#include <cstdio>#include <algorithm>#include <cstring>#include <climits>#include <cmath>#include <vector>using std::max;using std::swap;using std::vector;const int MAXN=1e5+5;int grt,sum_sz;int he[MAXN],fa[MAXN],sz[MAXN];int lv[MAXN],dis[MAXN][19];int val_sum[MAXN];long long cost_sum[MAXN],tofa_cost[MAXN];bool use[MAXN];vector<int> T[MAXN],DCT[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];inline void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int lv){for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){dis[v][lv]=dis[u][lv]+ed[i].w;DFS(v,u,lv);}}}void treeDC(int u,int lv){use[u]=true;::lv[u]=lv;DFS(u,0,lv);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(use[v]) continue;T[u].push_back(v);grt=0,sum_sz=sz[v];get_grt(v,0);fa[grt]=u;DCT[u].push_back(grt);treeDC(grt,lv+1);}}inline void mdf(int u,int w){for(int now=u;now;now=fa[now]){val_sum[now]+=w;cost_sum[now]+=(long long)w*dis[u][lv[now]];tofa_cost[now]+=(long long)w*dis[u][lv[fa[now]]];}}inline long long qry(int u){long long ret=0;for(int now=u;now;now=fa[now]){ret+=cost_sum[now];ret-=tofa_cost[now];ret+=(long long)val_sum[now]*(dis[u][lv[now]]-dis[u][lv[fa[now]]]);}return ret;}long long solve(int u){long long ret=qry(u);for(int i=0,lim=T[u].size();i<lim;++i){if(ret>qry(T[u][i]))return solve(DCT[u][i]);}return ret;}int main(){int n,q;scanf("%d%d",&n,&q);for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);addE(u,v,w),addE(v,u,w);}sum_sz=n;get_grt(1,0);int grt=::grt;treeDC(grt,1);for(int i=1,u,e;i<=q;++i){scanf("%d%d",&u,&e);mdf(u,e);printf("%lld\n",solve(grt));}return 0;}
代码:
#include <cstdio>#include <algorithm>#include <climits>using std::max;using std::swap;using std::sort;using std::lower_bound;using std::upper_bound;const int MAXN=150005;int n;struct monster{int age,id;monster(int _age=0,int _id=0):age(_age),id(_id){}bool operator <(const monster &that)const{return age<that.age;}static bool cmp_age(const monster &a,const monster &b){return a.age<b.age;}}devil[MAXN];class pDCT{private:int grt,sum_sz;int he[MAXN],sz[MAXN];int lv[MAXN],dis[MAXN][20],son_id[MAXN][20];bool use[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];void get_grt(int u,int fa){static int max_subT_sz[MAXN]={INT_MAX};sz[u]=1,max_subT_sz[u]=0;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){get_grt(v,u);sz[u]+=sz[v];max_subT_sz[u]=max(max_subT_sz[u],sz[v]);}}max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;}void DFS(int u,int fa,int lv){for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(!use[v] && v!=fa){son_id[v][lv]=son_id[u][lv];dis[v][lv]=dis[u][lv]+ed[i].w;DFS(v,u,lv);}}}void treeDC(int u,int lv){use[u]=true;this->lv[u]=lv;for(int i=he[u],v,idx=0;i;i=ed[i].nex){v=ed[i].to;if(!use[v]){son_id[v][lv]=idx++;dis[v][lv]=ed[i].w;DFS(v,0,lv);grt=0,sum_sz=sz[v];get_grt(v,0);treeDC(grt,lv+1);}}}public:void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void build(){sum_sz=n;get_grt(1,0);treeDC(grt,1);}private:struct node{int node_cnt;long long dis_sum,tofa_dis;node *s[3];node(){dis_sum=0;tofa_dis=node_cnt=0;s[0]=s[1]=s[2]=&Null;}node(node *u){*this=*u;}}*rt[MAXN];static node Null;public:pDCT(){rt[0]=&Null;}private:void ist(node *pre,node *&now,int u,int lv){now=new node(pre);now->dis_sum+=dis[u][lv];now->tofa_dis+=dis[u][lv-1];++now->node_cnt;if(lv!=this->lv[u])ist(pre->s[son_id[u][lv]],now->s[son_id[u][lv]],u,lv+1);}long long qry(node *now,int u,int lv){if(now==&Null) return 0;long long ret=0;ret+=now->dis_sum;ret-=now->tofa_dis;ret+=(long long)now->node_cnt*(dis[u][lv]-dis[u][lv-1]);if(lv!=this->lv[u])ret+=qry(now->s[son_id[u][lv]],u,lv+1);return ret;}long long qry(int now,int u){return qry(rt[now],u,1);}public:void ist(int pre,int now,int u){ist(rt[pre],rt[now],u,1);}long long qry(int l,int r,int u){return qry(r,u)-qry(l-1,u);}}T;pDCT::node pDCT::Null;inline void prepare(){sort(devil+1,devil+n+1,monster::cmp_age);for(int i=1;i<=n;++i)T.ist(i-1,i,devil[i].id);}inline void find_his(int &l,int &r){l=lower_bound(devil+1,devil+n+1,monster(l))-devil;r=upper_bound(devil+1,devil+n+1,monster(r))-devil-1;}int main(){int q,a;scanf("%d%d%d",&n,&q,&a);for(int i=1;i<=n;++i){scanf("%d",&devil[i].age);devil[i].id=i;}for(int i=1,u,v,w;i<n;++i){scanf("%d%d%d",&u,&v,&w);T.addE(u,v,w),T.addE(v,u,w);}T.build();prepare();long long lastans=0;for(int i=1,u,l,r;i<=q;++i){scanf("%d%d%d",&u,&l,&r);l=(l+lastans)%a;r=(r+lastans)%a;if(l>r) swap(l,r);find_his(l,r);lastans=T.qry(l,r,u);printf("%lld\n",lastans);}return 0;}
代码:
#include <cstdio>#include <algorithm>#include <cstdlib>#include <set>#include <stack>using std::swap;using std::set;using std::stack;const int MAXN=100005,MOD=1e9;int r[MAXN];class Treap{#define ls s[0]#define rs s[1]public:struct node{int val,key,cnt,sz;node *s[2];node(){val=key=cnt=sz=0; s[0]=s[1]=Null;}node(int _val):val(_val),key(rand()){cnt=sz=1,ls=rs=Null;}void* operator new(size_t){node *ret;if(mem_cur>mem_pool) ret=&*(mem_cur--);else ret=mem_bin.top(),mem_bin.pop();return ret;}void operator delete[](void *u){ //删除子树if(((node*)u)->ls!=Null) delete[](((node*)u)->ls);if(((node*)u)->rs!=Null) delete[](((node*)u)->rs);mem_bin.push((node*)u);}void upd(){sz= ls->sz + rs->sz + cnt;}}*rt;static node *Null;Treap(){rt=Null;}private:static node mem_pool[MAXN*100];static node *mem_cur;static stack<node*> mem_bin;private:static node* rot(node *u,bool lr){node *son=u->s[lr];u->s[lr]=son->s[lr^1];son->s[lr^1]=u;u->upd(),son->upd();return son;}static node* maintain(node *u,bool lr){if(u->key > u->s[lr]->key)u=rot(u,lr);return u;}public:static void ist(node *&u,int val){if(u==Null){u= new node(val);return;}if(u->val == val) ++u->cnt;else{bool lr=(val > u->val);ist(u->s[lr],val);u=maintain(u,lr);}u->upd();}void ist(int val){ist(rt,val);}void clear(){if(rt!=Null) delete[](rt);rt=Null;}int size(){return rt->sz;}int lt_cnt(int val){ //小于val的值的个数node *u=rt; int ret=0;while(u!=Null){if(u->val <= val){ret+= u->ls->sz + u->cnt;u=u->rs;}else u=u->ls;}return ret;}#undef ls#undef rs};Treap::node Treap::mem_pool[MAXN*100];Treap::node *Treap::Null=&mem_pool[0];Treap::node *Treap::mem_cur=Treap::mem_pool+(MAXN*100)-1;stack<Treap::node*> Treap::mem_bin;class SG_dync_DCT{//pre T ↓private:int he[MAXN];int anc[17][MAXN],dis[MAXN],de[MAXN];struct line{int to,nex,w;}ed[MAXN<<1];void addE(int u,int v,int w){static int cnt;ed[++cnt]=(line){v,he[u],w};he[u]=cnt;}void prepare_LCA(int u,int fa){ //计算新加入的点的倍增数组anc[0][u]=fa;for(int i=1;i<17;++i)anc[i][u]=anc[i-1][anc[i-1][u]];}int LCA(int u,int v){if(de[u]<de[v]) swap(u,v);for(int d=de[u]-de[v],i=0;d;d>>=1,++i){if(d&1) u=anc[i][u];}if(u==v) return v;for(int i=16;i>=0;--i){if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];}return anc[0][u];}int cal_dis(int u,int v){return dis[u]+dis[v]-(dis[LCA(u,v)]<<1);}public:int ist(int u,int fa,int w){ //新加入u点addE(u,fa,w),addE(fa,u,w);de[u]=de[fa]+1,dis[u]=dis[fa]+w;prepare_LCA(u,fa);return upd(u,fa);}//DCT ↓private:static const double ALPHA;int idx; //访问标号int use[MAXN],vis[MAXN]; //用不用该点,该点这次重构是否访问过int sz[MAXN];int fa[MAXN]; //上层重心set<int> dct[MAXN]; //重心树Treap plus[MAXN],minus[MAXN]; //和之前的动态点分治套路一样void DFS_del(int u){ //删除重心树的u的子树的treap和边//因为只有这里是正常下去遍历整棵子树的,//所以只能在这里标记等会可以到的点//后面标记会gg,在treeDC里遍历是跳跃的,//且这里只重建了一部分,没有重建的部分没有访问标记,//遍历着会绕上去到不该重建的地方use[u]=idx;plus[u].clear();for(set<int>::iterator iter=dct[u].begin();iter!=dct[u].end();++iter){minus[*iter].clear();DFS_del(*iter);}dct[u].clear();}int DFS_sz(int u,int fa){sz[u]=1;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(vis[v]!=idx && use[v]==idx && v!=fa)sz[u]+=DFS_sz(v,u);}return sz[u];}int get_grt(int u,int fa,int lim){for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(vis[v]!=idx && use[v]==idx && v!=fa){if(sz[v]>lim) return get_grt(v,u,lim);}}return u;}void DFS_ist(int u,int fa,int dis,Treap::node *&tp_rt){ //和3730那些一个套路Treap::ist(tp_rt,dis-r[u]);for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(vis[v]!=idx && use[v]==idx && v!=fa)DFS_ist(v,u,dis+ed[i].w,tp_rt);}}int treeDC(int u){ //这里由于有加点操作,treeDC()和之前略有不同u=get_grt(u,0,DFS_sz(u,0)>>1);vis[u]=idx;DFS_ist(u,0,0,plus[u].rt);Treap::node *minus_rt;for(int i=he[u],v;i;i=ed[i].nex){v=ed[i].to;if(vis[v]!=idx && use[v]==idx){minus_rt=Treap::Null;DFS_ist(v,u,ed[i].w,minus_rt);v=treeDC(v);this->fa[v]=u;dct[u].insert(v);minus[v].rt=minus_rt;}}return u;}void rebuild(int u){++idx;int fa=this->fa[u];if(fa) dct[fa].erase(u);DFS_del(u);//这个treap是针对fa而算的,所以可以保留//treeDC里的做法同理Treap::node *minus_rt=minus[u].rt;minus[u].rt=Treap::Null;u=treeDC(u);this->fa[u]=fa;if(fa) dct[fa].insert(u);minus[u].rt=minus_rt;}bool bal(int u){return plus[u].size()<ALPHA*plus[fa[u]].size()+0.5;}void maintain(int u){int cur=0;for(;fa[u];u=fa[u]){if(!bal(u)) cur=fa[u];}if(cur) rebuild(cur);}int upd(int u,int fa){ //更新:计算u所带来的影响this->fa[u]=fa;dct[fa].insert(u);int ret=0;for(int now=u,r=::r[u],fa,dis;now;now=fa){fa=this->fa[now];if(fa){dis=cal_dis(u,fa);ret+=plus[fa].lt_cnt(r-dis);ret-=minus[now].lt_cnt(r-dis);minus[now].ist(dis-r);}plus[now].ist(cal_dis(u,now)-r);}maintain(u);return ret;}}DCT;const double SG_dync_DCT::ALPHA=0.88;int main(){srand(125);int n;scanf("%*d%d",&n);long long lastans=0;for(int i=1,fa,w;i<=n;++i){scanf("%d%d%d",&fa,&w,&r[i]);fa^=lastans%MOD;lastans+=DCT.ist(i,fa,w);printf("%lld\n",lastans);}return 0;}