[BZOJ1984] 月下“毛景树”

Description

毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:  Change k w:将第k条树枝上毛毛果的个数改变为w个。  Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。  Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:  Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

Input

第一行一个正整数N。 接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。

Output

对于毛毛虫的每个询问操作,输出一个答案。

Sample Input

4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop

Sample Output

9
16

【Data Range】
1<=N<=100,000,操作+询问数目不超过100,000。
保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个

思路

树链剖分+线段树;
注意是边权

代码实现

  1 #include<cstdio>
  2 const int maxn=1e5+10;
  3 inline int min_(int x,int y){return x<y?x:y;}
  4 inline int max_(int x,int y){return x>y?x:y;}
  5 inline void swap_(int&x,int&y){x^=y,y^=x,x^=y;}
  6 int n;
  7 int a,b,c;
  8 int s[maxn],ss,ts[maxn<<2],tl[maxn<<2],tf[maxn<<2];
  9 int ps[maxn],pd[maxn],pf[maxn],pt[maxn],pp[maxn],pps,psz[maxn],pws[maxn];
 10 int h[maxn],ep[maxn],hs,et[maxn<<1],es[maxn<<1],en[maxn<<1],eid[maxn<<1];
 11 void dfs1(int k,int f,int d){
 12     pd[k]=d,pf[k]=f,psz[k]=1;
 13     for(int i=h[k];i;i=en[i])
 14     if(et[i]!=f){
 15         dfs1(et[i],k,d+1);
 16         psz[k]+=psz[et[i]],ps[et[i]]=es[i],ep[eid[i]]=et[i];
 17         if(psz[et[i]]>psz[pws[k]]) pws[k]=et[i];
 18     }
 19 }
 20 void dfs2(int k,int t){
 21     s[++pps]=ps[k],pp[k]=pps,pt[k]=t;
 22     if(pws[k]) dfs2(pws[k],t);
 23     for(int i=h[k];i;i=en[i])
 24     if(et[i]!=pf[k]&&et[i]!=pws[k]){
 25         dfs2(et[i],et[i]);
 26     }
 27 }
 28 void build(int k,int l,int r){
 29     if(l==r){ts[k]=s[++ss];return;}
 30     int mid=l+r>>1,ls=k<<1,rs=ls|1;
 31     build(ls,l,mid);
 32     build(rs,mid+1,r);
 33     ts[k]=max_(ts[ls],ts[rs]);
 34 }
 35 void downl(int k,int ls,int rs){
 36     tf[ls]=tf[rs]=0;
 37     ts[ls]=ts[rs]=tl[ls]=tl[rs]=tl[k];
 38     tl[k]=0;
 39 }
 40 void downf(int k,int ls,int rs){
 41     ts[ls]+=tf[k],ts[rs]+=tf[k];
 42     tf[ls]+=tf[k],tf[rs]+=tf[k];
 43     tf[k]=0;
 44 }
 45 void change(int k,int l,int r,int al,int ar,int v){
 46     if(l==al&&r==ar){ts[k]=tl[k]=v,tf[k]=0;return;}
 47     int mid=l+r>>1,ls=k<<1,rs=ls|1;
 48     if(tl[k]) downl(k,ls,rs);
 49     if(tf[k]) downf(k,ls,rs);
 50     if(al<=mid) change(ls,l,mid,al,min_(ar,mid),v);
 51     if(ar>mid) change(rs,mid+1,r,max_(al,mid+1),ar,v);
 52     ts[k]=max_(ts[ls],ts[rs]);
 53 }
 54 void add(int k,int l,int r,int al,int ar,int v){
 55     if(l==al&&r==ar){ts[k]+=v,tf[k]+=v;return;}
 56     int mid=l+r>>1,ls=k<<1,rs=ls|1;
 57     if(tl[k]) downl(k,ls,rs);
 58     if(tf[k]) downf(k,ls,rs);
 59     if(al<=mid) add(ls,l,mid,al,min_(ar,mid),v);
 60     if(ar>mid) add(rs,mid+1,r,max_(al,mid+1),ar,v);
 61     ts[k]=max_(ts[ls],ts[rs]);
 62 }
 63 int query(int k,int l,int r,int al,int ar){
 64     if(l==al&&r==ar) return ts[k];
 65     int mid=l+r>>1,ls=k<<1,rs=ls|1,ret=0;
 66     if(tl[k]) downl(k,ls,rs);
 67     if(tf[k]) downf(k,ls,rs);
 68     if(al<=mid) ret=max_(ret,query(ls,l,mid,al,min_(ar,mid)));
 69     if(ar>mid) ret=max_(ret,query(rs,mid+1,r,max_(al,mid+1),ar));
 70     return ret;
 71 }
 72 int main(){
 73     scanf("%d",&n);
 74     for(int i=1;i<n;i++){
 75         scanf("%d%d%d",&a,&b,&c);
 76         ++hs,et[hs]=b,es[hs]=c,eid[hs]=i,en[hs]=h[a],h[a]=hs;
 77         ++hs,et[hs]=a,es[hs]=c,eid[hs]=i,en[hs]=h[b],h[b]=hs;
 78     }
 79     dfs1(1,1,1);
 80     dfs2(1,1);
 81     build(1,1,n);
 82     char ch[10];
 83     while(scanf("%s",ch)!=EOF){
 84         if(ch[0]=='C'){
 85             if(ch[1]=='h'){
 86                 scanf("%d%d",&a,&b);
 87                 change(1,1,n,pp[ep[a]],pp[ep[a]],b);
 88             }
 89             if(ch[1]=='o'){
 90                 scanf("%d%d%d",&a,&b,&c);
 91                 while(pt[a]!=pt[b]){
 92                     if(pd[pt[a]]<pd[pt[b]]) swap_(a,b);
 93                     change(1,1,n,pp[pt[a]],pp[a],c);
 94                     a=pf[pt[a]];
 95                 }
 96                 if(pd[a]>pd[b]) swap_(a,b);
 97                 if(pp[b]>pp[a]) change(1,1,n,pp[a]+1,pp[b],c);
 98             }
 99         }
100         if(ch[0]=='A'){
101             scanf("%d%d%d",&a,&b,&c);
102             while(pt[a]!=pt[b]){
103                 if(pd[pt[a]]<pd[pt[b]]) swap_(a,b);
104                 add(1,1,n,pp[pt[a]],pp[a],c);
105                 a=pf[pt[a]];
106             }
107             if(pd[a]>pd[b]) swap_(a,b);
108             if(pp[b]>pp[a]) add(1,1,n,pp[a]+1,pp[b],c);
109         }
110         if(ch[0]=='M'){
111             scanf("%d%d",&a,&b),c=0;
112             while(pt[a]!=pt[b]){
113                 if(pd[pt[a]]<pd[pt[b]]) swap_(a,b);
114                 c=max_(c,query(1,1,n,pp[pt[a]],pp[a]));
115                 a=pf[pt[a]];
116             }
117             if(pd[a]>pd[b]) swap_(a,b);
118             if(pp[b]>pp[a]) c=max_(c,query(1,1,n,pp[a]+1,pp[b]));
119             printf("%d\n",c);
120         }
121         if(ch[0]=='S') return 0;
122     }
123 }

 我代码常数巨大,您怕不怕?

1984Accepted14180 kb4284 msC++/Edit3716 B2017-06-10 15:01:51

转载于:https://www.cnblogs.com/J-william/p/6978811.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值