洛谷 P2590 [ZJOI2008]树的统计(线段树,树链剖分)

传送门


解题思路

关于两点之间的最短距离的区间操作,很显然是树链剖分。

因为既有区间和还有区间最大值,所以我们建立两个线段树。

然后就是树剖的常规操作了。

AC代码

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 using namespace std;
  8 const int maxn=100005;
  9 int n,q,v[maxn],cnt,dep[maxn],siz[maxn],tp[maxn],son[maxn],f[maxn];
 10 int s1[maxn*4],s2[maxn*4],p[maxn];
 11 int id[maxn],rk[maxn];
 12 struct Edge{
 13     int v,next;
 14 }e[maxn];
 15 void insert(int u,int v){
 16     cnt++;
 17     e[cnt].v=v;
 18     e[cnt].next=p[u];
 19     p[u]=cnt;
 20 }
 21 void dfs1(int fa,int u,int deep){
 22     f[u]=fa;
 23     dep[u]=deep;
 24     siz[u]=1;
 25     for(int i=p[u];i!=-1;i=e[i].next){
 26         if(e[i].v==fa) continue;
 27         dfs1(u,e[i].v,deep+1);
 28         siz[u]+=siz[e[i].v];
 29         if(siz[e[i].v]>siz[son[u]]) son[u]=e[i].v;
 30     }
 31 }
 32 void dfs2(int fa,int u,int top){
 33     tp[u]=top;
 34     cnt++;
 35     id[u]=cnt;
 36     rk[cnt]=u;
 37     if(!son[u]) return;
 38     dfs2(u,son[u],top);
 39     for(int i=p[u];i!=-1;i=e[i].next){
 40         if(e[i].v==son[u]||e[i].v==fa) continue;
 41         dfs2(u,e[i].v,e[i].v);
 42     }
 43 }
 44 void build(int id,int l,int r){
 45     if(l==r){
 46         s1[id]=s2[id]=v[rk[l]];
 47         return;
 48     }
 49     int mid=(l+r)/2;
 50     build(id*2,l,mid);
 51     build(id*2+1,mid+1,r);
 52     s1[id]=s1[id*2]+s1[id*2+1];
 53     s2[id]=max(s2[id*2],s2[id*2+1]);
 54 }
 55 void add(int id,int x,int l,int r,int value){
 56     if(l==r){
 57         s1[id]=value;
 58         s2[id]=value;
 59         return;
 60     }
 61     int mid=(l+r)/2;
 62     if(x<=mid) add(id*2,x,l,mid,value);
 63     if(x>mid)  add(id*2+1,x,mid+1,r,value);
 64     s1[id]=s1[id*2]+s1[id*2+1];
 65     s2[id]=max(s2[id*2],s2[id*2+1]);
 66 }
 67 int querymax(int id,int x,int y,int l,int r){
 68     if(x<=l&&r<=y) return s2[id];
 69     int mid=(l+r)/2;
 70     int res=-9999999;
 71     if(x<=mid) res=max(res,querymax(id*2,x,y,l,mid));
 72     if(mid2+1,x,y,mid+1,r));
 73     return res; 
 74 }
 75 int querysum(int id,int x,int y,int l,int r){
 76     if(x<=l&&r<=y) return s1[id];
 77     int mid=(l+r)/2;
 78     int res=0;
 79     if(x<=mid) res+=querysum(id*2,x,y,l,mid);
 80     if(mid2+1,x,y,mid+1,r);
 81     return res; 
 82 }
 83 int main()
 84 {
 85     memset(p,-1,sizeof(p));
 86     cin>>n;
 87     for(int i=1;i){
 88         int a,b;
 89         cin>>a>>b;
 90         insert(a,b);
 91         insert(b,a);
 92     }
 93     for(int i=1;i<=n;i++) cin>>v[i];
 94     dfs1(-1,1,1);
 95     cnt=0;
 96     dfs2(-1,1,1);
 97     build(1,1,n);
 98     cin>>q;
 99     for(int i=1;i<=q;i++){
100         string s;
101         int a,b;
102         cin>>s>>a>>b;
103         if(s=="CHANGE"){
104             add(1,id[a],1,n,b);
105         }else{
106             if(s=="QSUM"){
107                 int ans=0;
108                 while(tp[a]!=tp[b]){
109                     if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
110                     ans+=querysum(1,id[tp[a]],id[a],1,n);
111                     a=f[tp[a]];
112                 }
113                 if(dep[a]<dep[b]) swap(a,b);
114                 ans+=querysum(1,id[b],id[a],1,n);
115                 cout<endl;
116             }else{
117                 int ans=-9999999;
118                 while(tp[a]!=tp[b]){
119                     if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
120                     ans=max(ans,querymax(1,id[tp[a]],id[a],1,n));
121                     a=f[tp[a]];
122                 }
123                 if(dep[a]<dep[b]) swap(a,b);
124                 ans=max(ans,querymax(1,id[b],id[a],1,n));
125                 cout<endl;
126             }
127         }
128     }    
129     return 0;
130 }

 

你可能感兴趣的:(洛谷 P2590 [ZJOI2008]树的统计(线段树,树链剖分))