HZOJ 模板(ac)

调了一天,恶心死我了……作者的题解水的一b……

测试点1~6:

暴力修改查询即可,期望得分30。

测试点7~14:

k=1e5,相当于没有限制,那么对于树上每个点建权值线段树,线段树合并即可。

期望的分40,结合算法1 70分。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #define MAXN 100010
  6 #define LL long long
  7 #define int LL
  8 #define ma(x,y) memset(x,y,sizeof(x))
  9 using namespace std;
 10 struct edge
 11 {
 12     int u,v,nxt;
 13     #define u(x) ed[x].u
 14     #define v(x) ed[x].v
 15     #define n(x) ed[x].nxt
 16 }ed[MAXN*2];
 17 int first[MAXN],num_e;
 18 #define f(x) first[x]
 19 int n,m,k[MAXN],Q,tc[MAXN];
 20 struct tree
 21 {
 22     int ls,rs,sum;    
 23     #define ls(x) tr[x].ls
 24     #define rs(x) tr[x].rs
 25     #define sum(x) tr[x].sum
 26 }tr[MAXN*200];
 27 int cnt,T[MAXN];
 28 int sum[1010][1010],fa[MAXN],maxc;
 29 void add(int &x,int l,int r,int L,int R)
 30 {
 31     if(!x)x=++cnt;    
 32     if(l==r){sum(x)|=1;return;}
 33     int mid=(l+r)>>1;
 34     if(L<=mid)add(ls(x),l,mid,L,R);
 35     if(R>mid) add(rs(x),mid+1,r,L,R);
 36     sum(x)=sum(ls(x))+sum(rs(x));
 37 }
 38 int ask(int x,int l,int r,int L,int R)
 39 {
 40     if(l>=L&&r<=R)return sum(x);
 41     int mid=(l+r)>>1,ans=0;
 42     if(L<=mid)ans+=ask(ls(x),l,mid,L,R);
 43     if(R>mid) ans+=ask(rs(x),mid+1,r,L,R);
 44     return ans;
 45 }
 46 int merge(int x,int y)
 47 {    
 48     if(!x||!y)return x+y;
 49     ls(x)=merge(ls(x),ls(y));
 50     rs(x)=merge(rs(x),rs(y));
 51     if(!ls(x)&&!rs(x))sum(x)=sum(x)|sum(y);
 52     else sum(x)=sum(ls(x))+sum(rs(x));
 53     return x;
 54 }
 55 int ans[MAXN],x[MAXN],c[MAXN];
 56 void dfs(int x,int fa)
 57 {
 58     for(int i=f(x);i;i=n(i))
 59     if(v(i)!=fa)
 60     {    
 61         dfs(v(i),x);
 62         ans[v(i)]=ask(T[v(i)],1,maxc,1,maxc);
 63         T[x]=merge(T[x],T[v(i)]);
 64     }
 65 }
 66 void dfs2(int x,int ff)
 67 {
 68     fa[x]=ff;
 69     for(int i=f(x);i;i=n(i))
 70     if(v(i)!=ff)
 71         dfs2(v(i),x);
 72 }
 73 inline int read();
 74 inline void adde(int u,int v);
 75 signed main()
 76 {
 77     n=read();int tu,tv;
 78     for(int i=1;i<n;i++)
 79     {    
 80         tu=read(),tv=read();    
 81         adde(tu,tv),adde(tv,tu);
 82     }
 83     for(int i=1;i<=n;i++)k[i]=read();    
 84     m=read();
 85     dfs2(1,0);
 86     if(n<=1000&&m<=1000)//暴力
 87     {
 88         LL tem,ac;LL x,c;
 89         for(int i=1;i<=m;i++)
 90         {
 91             x=read();c=read();
 92             maxc=max(maxc,c);
 93             tem=x;
 94             while(tem)
 95             {
 96                 if(sum[tem][0]<k[tem])
 97                 sum[tem][0]++,sum[tem][c]++;
 98                 tem=fa[tem];
 99             }
100         }
101         Q=read();
102         for(int i=1;i<=Q;i++)    
103         {
104             tem=read();ac=0;
105             for(int j=1;j<=maxc;j++)
106             if(sum[tem][j]!=0)ac++;
107             printf("%lld
",ac);
108         }
109         return 0;
110     }
111     for(int i=1;i<=m;i++)
112     {
113         x[i]=read(),c[i]=read(),tc[i]=c[i];
114         maxc=max(maxc,c[i]);
115     }
116     sort(tc+1,tc+1+m);maxc=m;
117     int ooo=unique(tc+1,tc+1+m)-tc-1;
118     for(int i=1;i<=m;i++)
119         c[i]=lower_bound(tc+1,tc+ooo+1,c[i])-tc;
120     for(int i=1;i<=m;i++)
121         add(T[x[i]],1,maxc,c[i],c[i]);
122     dfs(1,0);
123     Q=read();
124     ans[1]=ask(T[1],1,maxc,1,maxc);
125     for(int i=1;i<=Q;i++)
126     {
127         x[i]=read();printf("%lld
",ans[x[i]]);
128     }
129 }
130 inline int read()
131 {
132     int s=0,f=1;char a=getchar();
133     while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();    }
134     while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
135     return s*f;
136 }
137 inline void adde(int u,int v)
138 {
139     ++num_e;
140     u(num_e)=u;
141     v(num_e)=v;
142     n(num_e)=f(u);
143     f(u)=num_e;
144 }
View Code

测试点15~20:

最恶心的几个点,用到了树上启发式合并+树链剖分思想。

考虑以时间为线段树下标建立权值线段树,维护这段时间内小球的颜色种类数以及小球总数,用一个桶记录每个颜色出现的最早时间。对于每个节点建立一个vector,将关于这个节点的操作color,time二元组扔到这个节点的vector中。

首先一边dfs求出每个点的重儿子,要用重儿子来保证复杂度,证明见这里

这里先说一下不保证复杂度但是好理解而且可以救回来的思路:

然后第二遍dfs统计答案:先处理儿子(注意每次要清空桶,但是不要memset),然后将这个节点的所有操作扔到他的重儿子的vector中,互换(相当于将重儿子的操作扔到这个节点),然后枚举儿子,将其他儿子的操作合并,接下来就是统计这个点的答案了:首先确保此时桶是空的,然后枚举这个节点vector中的操作,如果当前小球未出现过直接更新线段树,如果在一个更晚的时间出现则在那个时间种类数减1,这个时间种类数+1。最后个数加1.然后说一下线段树的查询操作,和主席树的思想类似(直接上代码):

 1 int ask(int x,int l,int r,int num)
 2 {
 3     if(num<=0)return 0;
 4     if(l==r)return sum(x);        
 5     int ans=0,mid=(l+r)>>1;
 6     if(num(ls(x))<=num)    
 7     {
 8         ans+=sum(ls(x));
 9         ans+=ask(rs(x),mid+1,r,num-num(ls(x)));
10         return ans;
11     }
12     else return ask(ls(x),l,mid,num);
13 }
  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #define MAXN 100010
  7 #define LL long long
  8 #define MP(a,b) make_pair(a,b)
  9 #define ma(x) memest(x,0,sizeof(x))
 10 using namespace std;
 11 struct edge
 12 {
 13     int u,v,nxt;
 14     #define u(x) ed[x].u
 15     #define v(x) ed[x].v
 16     #define n(x) ed[x].nxt
 17 }ed[MAXN*2];
 18 int first[MAXN],num_e;
 19 #define f(x) first[x]
 20 int n,m,k[MAXN],Q,tc[MAXN];
 21 vector<pair<int,int> >cz[MAXN];
 22 struct tree
 23 {
 24     int ls,rs,sum,num;    
 25     #define ls(x) tr[x].ls
 26     #define rs(x) tr[x].rs
 27     #define sum(x) tr[x].sum    
 28     #define num(x) tr[x].num
 29 }tr[MAXN*1000];
 30 int cnt,T[MAXN],maxc;
 31 int ans[MAXN],x[MAXN],c[MAXN];
 32 int t[MAXN];
 33 int son[MAXN],size[MAXN];
 34 void add(int &x,int l,int r,int t,int tx,int y)
 35 {
 36     if(!x)x=++cnt;
 37     if(l==r){sum(x)+=tx;num(x)+=y;return;}
 38     int mid=(l+r)>>1;
 39     if(t<=mid)add(ls(x),l,mid,t,tx,y);
 40     else add(rs(x),mid+1,r,t,tx,y);
 41     sum(x)=sum(ls(x))+sum(rs(x));
 42     num(x)=num(ls(x))+num(rs(x));
 43 }
 44 int ask(int x,int l,int r,int num)
 45 {
 46     if(num<=0)return 0;
 47     if(l==r)return sum(x);        
 48     int ans=0,mid=(l+r)>>1;
 49     if(num(ls(x))<=num)    
 50     {
 51         ans+=sum(ls(x));
 52         ans+=ask(rs(x),mid+1,r,num-num(ls(x)));
 53         return ans;
 54     }
 55     else return ask(ls(x),l,mid,num);
 56 }
 57 void merge(int x,int y)
 58 {    
 59     for(int i=0;i<cz[y].size();i++)
 60         cz[x].push_back(cz[y][i]);
 61     cz[y].clear();
 62 }
 63 void clear(int x)
 64 {    
 65     for(int i=0;i<cz[x].size();i++)
 66         t[cz[x][i].first]=0;
 67 }
 68 void dfs2(int x,int fa)
 69 {    
 70     for(int i=f(x);i;i=n(i))
 71     if(v(i)!=fa)
 72     {
 73         dfs2(v(i),x);
 74         clear(v(i));
 75     }
 76     if(son[x])
 77     {
 78         merge(son[x],x);
 79         swap(cz[son[x]],cz[x]);
 80     }
 81     for(int i=f(x);i;i=n(i))
 82     if(v(i)!=fa)merge(x,v(i));
 83     for(int i=0;i<cz[x].size();i++)
 84     {
 85         int t1=cz[x][i].first,t2=cz[x][i].second;
 86         if(!t[t1])    
 87             add(T[x],1,m,t2,1,0),t[t1]=t2;
 88         else if(t[t1]>t2)
 89         {
 90             add(T[x],1,m,t[t1],-1,0);
 91             add(T[x],1,m,t2,1,0);
 92             t[t1]=t2;
 93         }
 94         add(T[x],1,m,t2,0,1);
 95     }
 96     ans[x]=ask(T[x],1,m,k[x]);
 97 }
 98 inline int read();
 99 void dfs(int x,int fa);
100 inline void adde(int u,int v);
101 signed main()
102 {
103 //    freopen("in.txt","r",stdin);
104 
105     n=read();int tu,tv;
106     for(int i=1;i<n;i++)
107     {    
108         tu=read(),tv=read();    
109         adde(tu,tv),adde(tv,tu);
110     }
111     for(int i=1;i<=n;i++)k[i]=read();    
112     m=read();
113     for(int i=1;i<=m;i++)
114     {
115         x[i]=read(),c[i]=read(),tc[i]=c[i];
116         maxc=max(maxc,c[i]);
117     }
118     sort(tc+1,tc+1+m);maxc=m;
119     int ooo=unique(tc+1,tc+1+m)-tc-1;
120     for(int i=1;i<=m;i++)
121         c[i]=lower_bound(tc+1,tc+ooo+1,c[i])-tc;
122     for(int i=1;i<=m;i++)
123         cz[x[i]].push_back(MP(c[i],i));
124     dfs(1,0);
125     dfs2(1,0);
126     Q=read();
127     for(int i=1;i<=Q;i++)
128         x[i]=read(),printf("%d
",ans[x[i]]);
129 }
130 inline int read()
131 {
132     int s=0,f=1;char a=getchar();
133     while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();    }
134     while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
135     return s*f;
136 }
137 inline void adde(int u,int v)
138 {
139     ++num_e;
140     u(num_e)=u;
141     v(num_e)=v;
142     n(num_e)=f(u);
143     f(u)=num_e;
144 }
145 void dfs(int x,int fa)
146 {
147     size[x]=1;
148     for(int i=f(x);i;i=n(i))
149     if(v(i)!=fa)
150     {
151         dfs(v(i),x);
152         size[x]+=size[v(i)];
153         if(size[v(i)]>size[son[x]])son[x]=v(i);
154     }
155 }
接近正解的T30代码

到这里就结束了,然后你应该就会发现你T30了,因为以上算法是不保证时间复杂度的,原因在于处理重儿子后清空桶花费了过长时间。但是如果不清空桶下面的答案查询就会出错,那怎么办呢?

其实可以在处理完所有轻儿子后在处理重儿子,此后不清空桶,而是直接T[x]=T[son[x]](根节点),直接从重儿子的线段树上开始修改,这样时间复杂度就有保证了。还有一点是这样要在最后才把重儿子的操作合并。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #define MAXN 100010
  7 #define LL long long
  8 #define int LL
  9 #define MP(a,b) make_pair(a,b)
 10 #define ma(x) memest(x,0,sizeof(x))
 11 using namespace std;
 12 struct edge
 13 {
 14     int u,v,nxt;
 15     #define u(x) ed[x].u
 16     #define v(x) ed[x].v
 17     #define n(x) ed[x].nxt
 18 }ed[MAXN*2];
 19 int first[MAXN],num_e;
 20 #define f(x) first[x]
 21 int n,m,k[MAXN],Q,tc[MAXN];
 22 vector<pair<int,int> >cz[MAXN];
 23 struct tree
 24 {
 25     int ls,rs,sum,num;    
 26     #define ls(x) tr[x].ls
 27     #define rs(x) tr[x].rs
 28     #define sum(x) tr[x].sum    
 29     #define num(x) tr[x].num
 30 }tr[MAXN*200];
 31 int cnt,T[MAXN],maxc;
 32 int ans[MAXN],x[MAXN],c[MAXN];
 33 int t[MAXN];
 34 int son[MAXN],size[MAXN];
 35 void add(int &x,int l,int r,int t,int tx,int y)
 36 {
 37     if(!x)x=++cnt;
 38     if(l==r){sum(x)+=tx;num(x)+=y;return;}
 39     int mid=(l+r)>>1;
 40     if(t<=mid)add(ls(x),l,mid,t,tx,y);
 41     else add(rs(x),mid+1,r,t,tx,y);
 42     sum(x)=sum(ls(x))+sum(rs(x));
 43     num(x)=num(ls(x))+num(rs(x));
 44 }
 45 int ask(int x,int l,int r,int num)
 46 {
 47     if(num<=0)return 0;
 48     if(l==r)return sum(x);        
 49     int ans=0,mid=(l+r)>>1;
 50     if(num(ls(x))<=num)    
 51     {
 52         ans+=sum(ls(x));
 53         ans+=ask(rs(x),mid+1,r,num-num(ls(x)));
 54         return ans;
 55     }
 56     else return ask(ls(x),l,mid,num);
 57 }
 58 void merge(int x,int y)
 59 {    
 60     for(int i=0;i<cz[y].size();i++)
 61         cz[x].push_back(cz[y][i]);
 62     cz[y].clear();
 63 }
 64 void clear(int x)
 65 {    
 66     for(int i=0;i<cz[x].size();i++)
 67         t[cz[x][i].first]=0;
 68 }
 69 void dfs2(int x,int fa)
 70 {    
 71     for(int i=f(x);i;i=n(i))
 72     if(v(i)!=fa&&v(i)!=son[x])
 73     {
 74         dfs2(v(i),x);
 75         clear(v(i));
 76     }
 77     if(son[x])dfs2(son[x],x);
 78     if(son[x])T[x]=T[son[x]];    
 79     for(int i=f(x);i;i=n(i))
 80     if(v(i)!=fa&&v(i)!=son[x])merge(x,v(i));
 81     for(int i=0;i<cz[x].size();i++)
 82     {
 83         int t1=cz[x][i].first,t2=cz[x][i].second;
 84         if(!t[t1])add(T[x],1,m,t2,1,0),t[t1]=t2;
 85         else if(t[t1]>t2)
 86         {
 87             add(T[x],1,m,t[t1],-1,0);
 88             add(T[x],1,m,t2,1,0);
 89             t[t1]=t2;
 90         }
 91         add(T[x],1,m,t2,0,1);
 92     }
 93     ans[x]=ask(T[x],1,m,k[x]);
 94     if(son[x])
 95     {
 96         merge(son[x],x);
 97         swap(cz[son[x]],cz[x]);
 98     }
 99 }
100 inline int read();
101 void dfs(int x,int fa);
102 inline void adde(int u,int v);
103 signed main()
104 {
105 //    freopen("in.txt","r",stdin);
106 
107     n=read();int tu,tv;
108     for(int i=1;i<n;i++)
109     {    
110         tu=read(),tv=read();    
111         adde(tu,tv),adde(tv,tu);
112     }
113     for(int i=1;i<=n;i++)k[i]=read();    
114     m=read();
115     for(int i=1;i<=m;i++)
116     {
117         x[i]=read(),c[i]=read(),tc[i]=c[i];
118         maxc=max(maxc,c[i]);
119     }
120     sort(tc+1,tc+1+m);maxc=m;
121     int ooo=unique(tc+1,tc+1+m)-tc-1;
122     for(int i=1;i<=m;i++)
123         c[i]=lower_bound(tc+1,tc+ooo+1,c[i])-tc;
124     for(int i=1;i<=m;i++)
125         cz[x[i]].push_back(MP(c[i],i));
126     dfs(1,0);dfs2(1,0);
127     Q=read();
128     for(int i=1;i<=Q;i++)
129         x[i]=read(),printf("%lld
",ans[x[i]]);
130 }
131 inline int read()
132 {
133     int s=0,f=1;char a=getchar();
134     while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();    }
135     while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
136     return s*f;
137 }
138 inline void adde(int u,int v)
139 {
140     ++num_e;
141     u(num_e)=u;
142     v(num_e)=v;
143     n(num_e)=f(u);
144     f(u)=num_e;
145 }
146 void dfs(int x,int fa)
147 {
148     size[x]=cz[x].size();
149     for(int i=f(x);i;i=n(i))
150     if(v(i)!=fa)
151     {
152         dfs(v(i),x);
153         size[x]+=size[v(i)];
154         if(size[v(i)]>size[son[x]])son[x]=v(i);
155     }
156 }
完整代码
原文地址:https://www.cnblogs.com/Al-Ca/p/11264199.html