BZOJ3306: 树

n<=1e5的有根点权树,m<=1e5个操作:换根,修改点权,查询子树最小值。

维护子树信息--dfs序,至于换根只需要分类讨论一下现在根和查询点的关系。

如果查询的点是根节点,就输出整颗树的最小值。

如果查询的点5在1到7的路径上,那以7为根的时候查询5,就是整颗树排除粉红色部分--5的儿子中,是7的祖先的那棵子树,就是5的儿子中能走到7的那一个对应的子树。

其他情况,直接输出查询的子树。

所以再写一个lca就行了,这里写了链剖可以顺便把dfs序搞出来。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 //#include<assert.h>
  5 #include<math.h>
  6 #include<algorithm>
  7 //#include<iostream>
  8 using namespace std;
  9  
 10 int n,m;
 11 #define maxn 200011
 12 struct Edge{int to,next;}edge[maxn<<1];int first[maxn],val[maxn],le=2;
 13 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;}
 14 void insert(int x,int y) {in(x,y);in(y,x);}
 15 int size[maxn],hea[maxn],fa[maxn],top[maxn],dep[maxn],list[maxn],lp[maxn],rp[maxn],ll;
 16 void dfs1(int x,int f)
 17 {
 18     fa[x]=f;dep[x]=dep[f]+1;
 19     size[x]=1;hea[x]=0;
 20     for (int i=first[x];i;i=edge[i].next)
 21     {
 22         const Edge &e=edge[i];if (e.to==f) continue;
 23         dfs1(e.to,x);
 24         size[x]+=size[e.to];
 25         if (size[hea[x]]<size[e.to]) hea[x]=e.to;
 26     }
 27 }
 28 void dfs2(int x,int from)
 29 {
 30     top[x]=from;
 31     list[++ll]=x;lp[x]=ll;
 32     if (hea[x]) dfs2(hea[x],from);
 33     for (int i=first[x];i;i=edge[i].next)
 34     {
 35         const Edge &e=edge[i];if (e.to==hea[x] || e.to==fa[x]) continue;
 36         dfs2(e.to,e.to);
 37     }
 38     rp[x]=ll;
 39 }
 40 void treecut()
 41 {
 42     dep[0]=fa[0]=size[0]=ll=0;
 43     dfs1(1,0);
 44     dfs2(1,1);
 45 }
 46 int lca(int x,int y)
 47 {
 48     while (top[x]!=top[y])
 49     {
 50         if (dep[top[x]]<dep[top[y]]) {int t=x;x=y;y=t;}
 51         x=fa[top[x]];
 52     }
 53     return dep[x]<dep[y]?x:y;
 54 }
 55 int findimp(int x,int y)
 56 {
 57     int last;
 58     while (top[x]!=top[y])
 59     {
 60         last=top[y];
 61         y=fa[top[y]];
 62     }
 63     if (x==y) return last;
 64     return list[lp[x]+1];
 65 }
 66 struct SMT
 67 {
 68     struct Node
 69     {
 70         int Min;
 71         int l,r;
 72         int ls,rs;
 73     }a[maxn<<1];
 74     int size;
 75     SMT() {size=0;}
 76     void up(int x)
 77     {
 78         const int &p=a[x].ls,&q=a[x].rs;
 79         a[x].Min=min(a[p].Min,a[q].Min);
 80     }
 81     void build(int &x,int L,int R)
 82     {
 83         x=++size;
 84         a[x].l=L;a[x].r=R;
 85         if (L==R)
 86         {
 87             a[x].Min=val[list[L]];
 88             a[x].ls=a[x].rs=0;
 89         }
 90         else
 91         {
 92             const int mid=(L+R)>>1;
 93             build(a[x].ls,L,mid);
 94             build(a[x].rs,mid+1,R);
 95             up(x);
 96         }
 97     }
 98     void build() {int x;build(x,1,n);}
 99     int ql,qr,v;
100     void be(int x)
101     {
102         if (a[x].l==a[x].r && a[x].l==ql) {a[x].Min=v;return;}
103         const int mid=(a[x].l+a[x].r)>>1;
104         if (ql<=mid) be(a[x].ls);
105         else be(a[x].rs);
106         up(x);
107     }
108     void be(int x,int v)
109     {
110         ql=x;this->v=v;
111         be(1);
112     }
113     int query(int x)
114     {
115         if (ql<=a[x].l && a[x].r<=qr) return a[x].Min;
116         const int mid=(a[x].l+a[x].r)>>1;
117         int ans=0x3f3f3f3f;
118         if (ql<=mid) ans=min(ans,query(a[x].ls));
119         if (qr> mid) ans=min(ans,query(a[x].rs));
120         return ans;
121     }
122     int query(int L,int R)
123     {
124         if (L>R) return 0x3f3f3f3f;
125         ql=L;qr=R;
126         return query(1);
127     }
128 }t;
129 int nowroot;
130 int main()
131 {
132     scanf("%d%d",&n,&m);
133     int x,y;char s[3];
134     memset(first,0,sizeof(first));
135     for (int i=1;i<=n;i++)
136     {
137         scanf("%d%d",&x,&y);
138         if (x) insert(x,i);
139         val[i]=y;
140     }
141     treecut();
142     t.build();
143     nowroot=1;
144     while (m--)
145     {
146         scanf("%s",s);
147         if (s[0]=='E') scanf("%d",&nowroot);
148         else if (s[0]=='V') scanf("%d%d",&x,&y),t.be(lp[x],y);
149         else if (s[0]=='Q')
150         {
151             scanf("%d",&x);
152             if (x==nowroot) printf("%d\n",t.query(1,n));
153             else
154             {
155                 int l=lca(x,nowroot);
156                 if (l==nowroot || (l!=x && l!=nowroot)) printf("%d\n",t.query(lp[x],rp[x]));
157                 else
158                 {
159                     int tmp=findimp(x,nowroot);
160                     printf("%d\n",min(t.query(1,lp[tmp]-1),t.query(rp[tmp]+1,n)));
161                 }
162             }
163         }
164     }
165     return 0;
166 }
167 
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/7691289.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值