树链剖分(BZOJ 1036)

Notes:莫名其妙WA一定是数组开小了!!!

一句话树链剖分:将一棵树“剖分”为多条链再映射到线段树上维护

时间复杂度:O(n(logn)^2)

BZOJ 1036题意:

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

  1 #include <cstdio>
  2 inline int max(int a,int b)
  3 {
  4     return a>b?a:b;
  5 }
  6 inline void swap(int &a,int &b)
  7 {
  8     register int tmp=a;
  9     a=b;b=tmp;
 10 }
 11 inline void read(int &k)
 12 {
 13     register int f=1,c=getchar();k=0;
 14     while (c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
 15     while (c>='0'&&c<='9')k=k*10+c-'0',c=getchar();
 16     k*=f;
 17 }
 18 const int maxn=301000*2,inf=1<<30;
 19 struct node{
 20     int l,r,mx,sum;
 21 }tree[maxn];
 22 char s[233];
 23 bool vis[maxn];
 24 int n,a,b,q,tot,u,v,tmp,cnt;
 25 int last[maxn],nxt[maxn],to[maxn],depth[maxn],top[maxn],siz[maxn],pos[maxn],fa[maxn];
 26 void build(int l,int r,int cur)
 27 {
 28     tree[cur].l=l;tree[cur].r=r;
 29     if (l==r)return;
 30     register int mid=(l+r)>>1;
 31     build(l,mid,cur<<1);
 32     build(mid+1,r,cur<<1|1);
 33 }
 34 void change(int x,int t,int cur)
 35 {
 36     if (tree[cur].l==tree[cur].r){tree[cur].mx=tree[cur].sum=t;return;}
 37     register int mid=(tree[cur].l+tree[cur].r)>>1;
 38     if (x<=mid)change(x,t,cur<<1);else change(x,t,cur<<1|1);
 39     tree[cur].sum=tree[cur<<1].sum+tree[cur<<1|1].sum;
 40     tree[cur].mx=max(tree[cur<<1].mx,tree[cur<<1|1].mx);
 41 }
 42 int querymx(int l,int r,int cur)
 43 {
 44     if (l<=tree[cur].l&&tree[cur].r<=r)return tree[cur].mx;
 45     register int mid=(tree[cur].l+tree[cur].r)>>1,ans=-inf;
 46     if (l<=mid)ans=querymx(l,r,cur<<1);
 47     if (r>mid)ans=max(ans,querymx(l,r,cur<<1|1));
 48     return ans;
 49 }
 50 int querysum(int l,int r,int cur)
 51 {
 52     if (l<=tree[cur].l&&tree[cur].r<=r)return tree[cur].sum;
 53     register int ans=0,mid=(tree[cur].l+tree[cur].r)>>1;
 54     if (l<=mid)ans=querysum(l,r,cur<<1);
 55     if (r>mid)ans+=querysum(l,r,cur<<1|1);
 56     return ans;
 57 }
 58 void dfs(int now)
 59 {
 60     vis[now]=1;siz[now]=1;
 61     for (register int i=last[now];i;i=nxt[i])
 62     {
 63         if (vis[to[i]])continue;
 64         fa[to[i]]=now;
 65         depth[to[i]]=depth[now]+1;
 66         dfs(to[i]);
 67         siz[now]+=siz[to[i]];
 68     }
 69 }
 70 void _dfs(int now,int t)
 71 {
 72     register int p=0;
 73     pos[now]=++cnt;
 74     top[now]=t;
 75     for (register int i=last[now];i;i=nxt[i])
 76         if (depth[to[i]]>depth[now]&&siz[to[i]]>siz[p])p=to[i];
 77     if (!p)return;
 78     _dfs(p,t);
 79     for (register int i=last[now];i;i=nxt[i])
 80         if (depth[to[i]]>depth[now]&&to[i]!=p)_dfs(to[i],to[i]);
 81 }
 82 inline int solvemx(int a,int b)
 83 {
 84     register int ans=-inf;
 85     while(top[a]!=top[b])
 86     {
 87         if (depth[top[a]]<depth[top[b]])swap(a,b);
 88         ans=max(ans,querymx(pos[top[a]],pos[a],1));
 89         a=fa[top[a]];
 90     }
 91     if (pos[a]>pos[b])swap(a,b);
 92     return max(querymx(pos[a],pos[b],1),ans);
 93 }
 94 inline int solvesum(int a,int b)
 95 {
 96     register int ans=0;    
 97     while(top[a]!=top[b])
 98     {
 99         if (depth[top[a]]<depth[top[b]])swap(a,b);
100         ans+=querysum(pos[top[a]],pos[a],1);
101         a=fa[top[a]];
102     }
103     if (pos[a]>pos[b])swap(a,b);
104     return ans+querysum(pos[a],pos[b],1);
105 }
106 inline void work()
107 {
108     read(n);
109     for (register int i=1;i<n;i++)
110     {
111         read(u);read(v);
112         nxt[++tot]=last[u];
113         last[u]=tot;
114         to[tot]=v;
115         nxt[++tot]=last[v];
116         last[v]=tot;
117         to[tot]=u;
118     }
119     build(1,n,1);
120     depth[1]=1;
121     dfs(1);
122     _dfs(1,1);
123     for (register int i=1;i<=n;i++)
124     {
125         read(tmp);
126         change(pos[i],tmp,1);
127     }
128     read(q);
129     for (register int i=1;i<=q;i++)
130     {
131         scanf("%s",s);read(a);read(b);
132         if (s[3]=='X')//QMAX
133             printf("%d\n",solvemx(a,b));
134         else if (s[0]=='C')//CHANGE
135             change(pos[a],b,1);
136         else //QSUM
137             printf("%d\n",solvesum(a,b));
138     }
139 }
140 int main()
141 {
142     work();
143     return 0;
144 }
View Code

 

转载于:https://www.cnblogs.com/mczhuang/p/7647952.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值