【樹狀數組】CSU 1811 Tree Intersection (2016湖南省第十二屆大學生計算機程序設計競賽)

題目連接:php

  http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1811
ios

題目大意:c++

  一棵樹,N(2<=N<=105)個節點,每一個節點有一種顏色Ci(Ci<=N),問把每一條邊刪掉後,剩下的兩個聯通塊中顏色的交集的大小(就是兩邊都含有的顏色種數)。數組

題目思路:數據結構

  【樹狀數組】ide

  個人數據結構造詣不深,這題寫了暴力求每一個點的顏色數T了。看了別人的題解寫了超級久WA了好多才過。spa

  首先能夠知道,若是已知每一個節點的子樹中含有的顏色種數C和只出如今這棵子樹的顏色種數D,那麼這個節點和它的父親節點中間的那條邊被刪去後的答案就是C-D。.net

  因此問題變爲求以每一個節點爲根的子樹中的C和D值。而後我想到這裏就不知道要怎麼寫了。看了大神的題解纔有一點思路。(不過我感受大神的題解好像有點問題??)code

  首先轉化成dfs序,按照遍歷這棵樹的順序求出每一個節點的新的從小到大的標號q[u].b(父親標號先前於兒子),同時記下原先對應的節點標號q[u].idblog

  預處理出對於顏色ci,記pre[ci]爲ci上次出現的顏色位置,L[ci],R[ci]爲ci出現的最左最右端。而後按照新的dfs序標號從小到大作

  對於節點i,將pre[ci]到i之間的全部點ans+1(由於答案是一條條樹鏈統計的,不會計算到兄弟節點,實際影響的只有這個節點以上的父親節點,因此答案不會出錯,本質上至關於把L[ci]到R[ci]全部的點都ans+1,可是隻有有這種顏色的節點到根的樹鏈上的點會加上答案,這樣實際上是沒錯的)

  若是到了顏色的最右端,把這種顏色最左端左邊的答案刪掉(由於一開始pre默認是0,會把1~L[ci]中的答案+1,須要扣除,也能夠一開始就從L[ci]開始加)

  到達葉子結點後統計這條樹鏈的答案。以上的ans能夠用樹狀數組統計。

 

  1 //
  2 //by coolxxx
  3 //#include<bits/stdc++.h>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<string>
  7 #include<iomanip>
  8 #include<map>
  9 #include<stack>
 10 #include<queue>
 11 #include<set>
 12 #include<bitset>
 13 #include<memory.h>
 14 #include<time.h>
 15 #include<stdio.h>
 16 #include<stdlib.h>
 17 #include<string.h>
 18 //#include<stdbool.h>
 19 #include<math.h>
 20 #define min(a,b) ((a)<(b)?(a):(b))
 21 #define max(a,b) ((a)>(b)?(a):(b))
 22 #define abs(a) ((a)>0?(a):(-(a)))
 23 #define lowbit(a) (a&(-a))
 24 #define sqr(a) ((a)*(a))
 25 #define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
 26 #define mem(a,b) memset(a,b,sizeof(a))
 27 #define eps (1e-10)
 28 #define J 10000
 29 #define mod 1000000007
 30 #define MAX 0x7f7f7f7f
 31 #define PI 3.14159265358979323
 32 #pragma comment(linker,"/STACK:102400000,102400000")
 33 #define N 100004
 34 #define M 200004
 35 using namespace std;
 36 typedef long long LL;
 37 int cas,cass;
 38 int n,m,lll,ans;
 39 double anss;
 40 LL aans;
 41 int last[N],fa[N],c[N],pre[N],l[N],r[N],f[N],g[N],e[N];
 42 struct edge
 43 {
 44     int from,next,to;
 45 }a[M];
 46 struct xu
 47 {
 48     int b,id;
 49 }q[N];
 50 void add(int x,int y)
 51 {
 52     a[++lll].to=y;
 53     a[lll].from=x;
 54     a[lll].next=last[x];
 55     last[x]=lll;
 56 }
 57 bool cmp(xu aa,xu bb)
 58 {
 59     return aa.b<bb.b;
 60 }
 61 void dfs(int u,int father)
 62 {
 63     int i,v;
 64     q[u].b=++cas,q[u].id=u;//b爲新的按照dfs順序的標號,id爲原先標號
 65     for(i=last[u];i;i=a[i].next)
 66     {
 67         v=a[i].to;
 68         if(v==father)continue;
 69         dfs(v,u);
 70         e[q[v].b]=(i+1)>>1;//把新節點標號和原先的邊的標號對應起來
 71         fa[q[v].b]=q[u].b;//統計新節點標號的父親
 72     }
 73 }
 74 inline void modify(int x,int y)
 75 {
 76     int i;
 77     for(i=x;i<=n;i+=lowbit(i))f[i]+=y;
 78 }
 79 inline int getsum(int x)
 80 {
 81     int i,sum=0;
 82     for(i=x;i;i-=lowbit(i))sum+=f[i];
 83     return sum;
 84 }
 85 int main()
 86 {
 87     #ifndef ONLINE_JUDGE
 88     freopen("1.txt","r",stdin);
 89 //    freopen("2.txt","w",stdout);
 90     #endif
 91     int i,j,k;
 92     int x,y,z;
 93 //    init();
 94 //    for(scanf("%d",&cass);cass;cass--)
 95 //    for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
 96 //    while(~scanf("%s",s))
 97     while(~scanf("%d",&n))
 98     {
 99         lll=cas=0;mem(last,0);mem(l,0);mem(r,0);mem(pre,0);mem(f,0);
100         for(i=1;i<=n;i++)scanf("%d",c+i);
101         for(i=1;i<n;i++)
102         {
103             scanf("%d%d",&x,&y);
104             add(x,y),add(y,x);
105         }
106         dfs(1,0);
107         sort(q+1,q+1+n,cmp);
108         for(i=1,j=q[i].id;i<=n;i++,j=q[i].id)
109             if(!l[c[j]])l[c[j]]=i;//統計每種顏色出現的最左端
110         for(i=n,j=q[i].id;i;i--,j=q[i].id)
111             if(!r[c[j]])r[c[j]]=i;//統計每種顏色出現的最右端
112         for(i=1;i<=n;i++)
113         {
114             j=q[i].id;
115             modify(pre[c[j]]+1,1),modify(i+1,-1);//把上次這個顏色出現的位置到i之間的節點答案+1
116             pre[c[j]]=i;//pre記錄的是這個顏色上一次出現的位置
117             if(i==r[c[j]])modify(1,-1),modify(l[c[j]]+1,1);//若是這種顏色出現最右端在這個點,那麼把最左端左邊的全部節點答案-1,由於顏色最左端的答案不能統計在內
118             if(a[last[j]].to==q[fa[i]].id)//若是當前結點是葉子結點
119                 for(k=i;k!=1;k=fa[k])g[e[k]]=getsum(k);//統計從根到這個葉子結點的樹鏈的答案
120         }
121         for(i=1;i<n;i++)
122             printf("%d\n",g[i]);
123     }
124     return 0;
125 }
126 /*
127 //
128 
129 //
130 */
View Code
相關文章
相關標籤/搜索