[HZOI 2015]树黑白

【题目描述】

给定一棵树,要求维护以下操作:

1、M u 将u节点反色

2、Q u 查询u到所有黑色节点距离和

【输入格式】

第一行n,m 表示节点总数和操作次数

之后n-1行,每行u,v表示两个端点,w表示边权

之后m行,操作如题意

n,m<=200000,边权<=1000

一开始所有点均为白色

【输出格式】

输出每次Q的答案

【样例输入】

7 5

2 1 144

3 2 361

4 3 236

5 3 697

6 2 140

7 5 718

Q 4

M 4

Q 5

Q 1

Q 7

【样例输出】

0

933

741

1651

题解:

和上一题差不多,多了一个修改操作。

还是动态点分,每个节点储存两个数,分别表示整棵子树到根和到根节点的父节点的距离和。

容斥一下就好。

  1 //Never forget why you start
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<cmath>
  7 #include<algorithm>
  8 #define inf (2147483647)
  9 using namespace std;
 10 int n,m,a[200005],lim;
 11 struct node{
 12   int next,to,dis;
 13 }edge[400005];
 14 int head[200005],size;
 15 void putin(int from,int to,int dis){
 16   size++;
 17   edge[size].next=head[from];
 18   edge[size].to=to;
 19   edge[size].dis=dis;
 20   head[from]=size;
 21 }
 22 int fa[200005][20],dis[200005],depth[200005];
 23 void dfs1(int r,int father){
 24   int i;
 25   fa[r][0]=father;
 26   depth[r]=depth[father]+1;
 27   for(i=head[r];i!=-1;i=edge[i].next){
 28     int y=edge[i].to;
 29     if(y!=father){
 30       dis[y]=dis[r]+edge[i].dis;
 31       dfs1(y,r);
 32     }
 33   }
 34 }
 35 void make(){
 36   lim=log(n)/log(2);
 37   for(int i=1;i<=lim;i++)
 38     for(int j=1;j<=n;j++)
 39       fa[j][i]=fa[fa[j][i-1]][i-1];
 40 }
 41 int LCA(int x,int y){
 42   if(depth[x]<depth[y])swap(x,y);
 43   for(int i=lim;i>=0;i--)
 44     if(depth[fa[x][i]]>=depth[y])
 45       x=fa[x][i];
 46   if(x!=y){
 47     for(int i=lim;i>=0;i--)
 48       if(fa[x][i]!=fa[y][i])
 49     x=fa[x][i],y=fa[y][i];
 50     x=fa[x][0];
 51     y=fa[y][0];
 52   }
 53   return x;
 54 }
 55 int dist(int x,int y){
 56   int lca=LCA(x,y);
 57   return dis[x]+dis[y]-dis[lca]*2;
 58 }
 59 int tot,root,vis[200005],d[200005],ff[200005],cnt[200005];
 60 void getroot(int r,int father){
 61   int i;
 62   cnt[r]=1;d[r]=0;
 63   for(i=head[r];i!=-1;i=edge[i].next){
 64     int y=edge[i].to;
 65     if(y!=father&&!vis[y]){
 66       getroot(y,r);
 67       cnt[r]+=cnt[y];
 68       d[r]=max(d[r],cnt[y]);
 69     }
 70   }
 71   d[r]=max(d[r],tot-cnt[r]);
 72   if(d[root]>d[r])root=r;
 73 }
 74 void buildtree(int r,int father){
 75   int i,all=tot;
 76   ff[r]=father;vis[r]=1;
 77   for(i=head[r];i!=-1;i=edge[i].next){
 78     int y=edge[i].to;
 79     if(!vis[y]){
 80       if(cnt[y]>cnt[r])cnt[y]=all-cnt[r];tot=cnt[y];
 81       root=0;getroot(y,r);buildtree(root,r);
 82     }
 83   }
 84 }
 85 int p[200005][2];
 86 void insert(int x,int v){
 87   int i;
 88   for(i=x;ff[i];i=ff[i]){
 89     int len=dist(x,ff[i]);
 90     p[i][1]+=len*v;
 91     p[ff[i]][0]+=len*v;
 92   }
 93   for(i=x;i;i=ff[i])cnt[i]+=v;
 94 }
 95 int find(int x){
 96   int i,ans=p[x][0];
 97   for(i=x;ff[i];i=ff[i]){
 98     int len=dist(x,ff[i]);
 99     ans+=p[ff[i]][0];
100     ans-=p[i][1];
101     ans+=(cnt[ff[i]]-cnt[i])*len;
102   }
103   return ans;
104 }
105 void clean(){
106   memset(head,-1,sizeof(head));
107   size=0;
108 }
109 int main(){
110   freopen("A_Tree.in","r",stdin);
111   freopen("A_Tree.out","w",stdout);
112   int i,j;
113   clean();
114   scanf("%d%d",&n,&m);
115   for(i=1;i<n;i++){
116     int u,v,l;
117     scanf("%d%d%d",&u,&v,&l);
118     putin(u,v,l);
119     putin(v,u,l);
120   }
121   dfs1(1,0);make();
122   tot=n;root=0;d[0]=inf;
123   getroot(1,0);buildtree(root,0);
124   for(i=1;i<=n;i++)if(!ff[i]){root=i;break;}
125   char s[10];
126   memset(cnt,0,sizeof(cnt));
127   while(m--){
128     scanf("%s",s);
129     if(s[0]=='Q'){
130       int x;
131       scanf("%d",&x);
132       printf("%d\n",find(x));
133     }
134     else{
135       int x;
136       scanf("%d",&x);
137       a[x]^=1;
138       if(a[x])insert(x,1);
139       else insert(x,-1);
140     }
141   }
142   return 0;
143 }

 

posted @ 2018-01-22 08:45  kakakakakaka  阅读(314)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效