【NOI2015】软件包管理器

NOI2015的试题,一道树链剖分的模板题
主要过程:树剖完成后对线段树进行区间修改,区间查询。
代码较长,很考验代码能力

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 typedef long long ll;
  5 inline int abs(int x) {
  6     return x>0?x:-x;
  7 }
  8 inline int read() {
  9     int ret=0,f=1;
 10     char c=getchar();
 11     while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
 12     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
 13     return ret*f;
 14 }
 15 using namespace std;
 16 int n,q;
 17 struct edge {
 18     int next,to;
 19 }a[100010<<1];
 20 int num,head[100010<<1];
 21 char in[100];
 22 inline void add(int from,int to) {
 23     a[++num].next=head[from]; a[num].to=to; head[from]=num;
 24     swap(from,to);
 25     a[++num].next=head[from]; a[num].to=to; head[from]=num;
 26 }
 27 int fa[100010],d[100010],seg[100010],rev[100010],top[100010],son[100010];
 28 int data[100010<<2],tag[100010<<2],size[100010];
 29 void dfs1(int u,int f) {
 30     d[u]=d[f]+1;
 31     fa[u]=f;
 32     size[u]=1;
 33     for(int i=head[u];i;i=a[i].next) {
 34         int v=a[i].to;
 35         if(v==f) continue ;
 36         dfs1(v,u);
 37         size[u]+=size[v];
 38         if(size[v]>size[son[u]]) son[u]=v;
 39     }
 40 }
 41 void dfs2(int u,int fa) {
 42     if(son[u]) {
 43         seg[son[u]]=++seg[0];
 44         rev[seg[0]]=son[u];
 45         top[son[u]]=top[u];
 46         dfs2(son[u],u);
 47     }
 48     for(int i=head[u];i;i=a[i].next) {
 49         int v=a[i].to;
 50         if(!top[v]) {
 51             seg[v]=++seg[0];
 52             top[v]=v;
 53             rev[seg[0]]=v;
 54             dfs2(v,u);
 55         }
 56     }
 57 }
 58 void build(int now,int l,int r) {
 59     tag[now]=-1;
 60     if(l==r) {
 61         tag[now]=data[now]=0;
 62         return ;
 63     }
 64     int mid=l+r>>1;
 65     build(now<<1,l,mid);
 66     build(now<<1|1,mid+1,r);
 67 }
 68 void pushdown(int now,int len) {
 69     if(tag[now]==-1) return ;
 70     tag[now<<1]=tag[now<<1|1]=tag[now];
 71     data[now<<1]=tag[now]*(len-(len>>1));
 72     data[now<<1|1]=tag[now]*(len>>1);
 73     tag[now]=-1;
 74 }
 75 void updata(int now,int l,int r,int x,int y,int val) {
 76     if(x<=l&&r<=y) {
 77         tag[now]=val;
 78         data[now]=val*(r-l+1);
 79         return ;
 80     }
 81     pushdown(now,r-l+1);
 82     int mid=l+r>>1;
 83     if(x<=mid) updata(now<<1,l,mid,x,y,val);
 84     if(y>mid) updata(now<<1|1,mid+1,r,x,y,val);
 85     data[now]=data[now<<1]+data[now<<1|1];
 86 }
 87 void find(int x,int y) {
 88     while(top[x]!=top[y]) {
 89         if(d[top[x]]<d[top[y]]) swap(x,y);
 90         updata(1,1,seg[0],seg[top[x]],seg[x],1);
 91         x=fa[top[x]];
 92     }
 93     if(d[x]>d[y]) swap(x,y);
 94     updata(1,1,seg[0],seg[x],seg[y],1);
 95 }
 96 int main() {
 97     n=read();
 98     for(int i=2;i<=n;i++) add(i,read()+1);
 99     dfs1(1,0);
100     seg[0]=seg[1]=rev[1]=top[1]=1;
101     dfs2(1,0);
102     build(1,1,seg[0]);
103     q=read();
104     while(q--) {
105         scanf("%s",in+1);
106         int x=read()+1;
107         if(in[1]=='i') {
108             int sum1=data[1];
109             find(1,x);
110             int sum2=data[1];
111             printf("%d
",abs(sum1-sum2));
112         }
113         else {
114             int sum1=data[1];
115             updata(1,1,seg[0],seg[x],seg[x]+size[x]-1,0);
116             int sum2=data[1];
117             printf("%d
",abs(sum1-sum2));
118         }
119     }
120     return 0;
121 }
AC Code

注意线段树的标记操作

原文地址:https://www.cnblogs.com/shl-blog/p/10541123.html