5.27 Test
思路:
各种方法。
代码:
1.遍历树1 时间 0.314 s 平均内存 2.96 MB
1 #include<cstdio> 2 using namespace std; 3 const int N=100005; 4 5 int n,Enum,cnt,H[N<<1],fa[N],Ans;//,Dfn[N],Size[N]; 6 struct Edge 7 { 8 int to,nxt; 9 }e[N<<1]; 10 11 int read() 12 { 13 int now=0;bool f=0;char c=getchar(); 14 while(c<'0'||c>'9') 15 { 16 if(c=='-')f=1; 17 c=getchar(); 18 } 19 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 20 return f?-now:now; 21 } 22 23 void AddEdge(int u,int v) 24 { 25 e[++Enum].to = v; 26 e[Enum].nxt = H[u]; 27 H[u] = Enum; 28 } 29 30 void DFS(int cur,int f,int cmp) 31 { 32 // Dfn[cur]=++cnt;//printf("%d:%d\n",cnt,cur); 33 for(int i=H[cur];i;i=e[i].nxt) 34 { 35 int to=e[i].to;//printf("%d OK\n",cur); 36 if(to!=f) 37 { 38 if(to<cmp) ++Ans; 39 DFS(to,cur,cmp); 40 // Ans[cur]+=Ans[to]; 41 // Size[cur]+=Size[to]+1; 42 } 43 } 44 } 45 46 int main() 47 { 48 // freopen("counttree.in","r",stdin); 49 // freopen("counttree.out","w",stdout); 50 n=read(); 51 int sta; 52 for(int i=1;i<=n;i++) 53 { 54 fa[i]=read(); 55 if(fa[i]==0) sta=i; 56 else AddEdge(fa[i],i),AddEdge(i,fa[i]); 57 } 58 // DFS(sta,0); 59 // printf("%d ",sta); 60 // for(int i=1;i<=n;i++) 61 // printf("%d ",Ans[i]); 62 for(int i=1;i<=n;i++) 63 { 64 Ans=0; 65 DFS(i,fa[i],i); 66 printf("%d\n",Ans); 67 } 68 fclose(stdin);fclose(stdout); 69 return 0; 70 }
2.遍历父节点 时间 0.151 s 平均内存 1.05 MB
1 #include<cstdio> 2 using namespace std; 3 const int N=100005; 4 5 int n,fa[N],Num[N]; 6 7 int read() 8 { 9 int now=0;bool f=0;char c=getchar(); 10 while(c<'0'||c>'9') 11 { 12 if(c=='-')f=1; 13 c=getchar(); 14 } 15 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 16 return f?-now:now; 17 } 18 19 int main() 20 { 21 freopen("counttree.in","r",stdin); 22 freopen("counttree.out","w",stdout); 23 n=read(); 24 for(int a,i=1;i<=n;i++) 25 a=read(),fa[i]=a; 26 for(int i=1;i<=n;i++) 27 { 28 int t=i; 29 while(fa[t]) 30 { 31 if(fa[t]>i) 32 ++Num[fa[t]]; 33 t=fa[t]; 34 } 35 } 36 for(int i=1;i<=n;i++) 37 printf("%d\n",Num[i]); 38 fclose(stdin);fclose(stdout); 39 return 0; 40 }
3.DFS序+树状数组(参考) 时间 0.154 s 内存使用 3.72MB
1 #include<cstdio> 2 using namespace std; 3 const int N=100005; 4 5 int n,Enum,cnt,in[N],out[N],H[N<<1],Tree[N]; 6 struct Edge 7 { 8 int to,nxt; 9 }e[N<<1]; 10 11 int read() 12 { 13 int now=0;bool f=0;char c=getchar(); 14 while(c<'0'||c>'9') 15 { 16 if(c=='-')f=1; 17 c=getchar(); 18 } 19 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 20 return f?-now:now; 21 } 22 23 void AddEdge(int u,int v) 24 { 25 e[++Enum].to = v; 26 e[Enum].nxt = H[u]; 27 H[u] = Enum; 28 } 29 30 void DFS(int cur,int f) 31 { 32 in[cur]=++cnt; 33 for(int i=H[cur];i;i=e[i].nxt) 34 { 35 int to=e[i].to; 36 if(to!=f) 37 DFS(to,cur); 38 } 39 out[cur]=cnt; 40 } 41 42 inline int lb(int x) 43 { 44 return x&-x; 45 } 46 void Update(int p,int v) 47 { 48 while(p<=n) 49 Tree[p]+=v,p+=lb(p); 50 } 51 int Query(int p) 52 { 53 int tmp=0; 54 while(p) 55 tmp+=Tree[p],p-=lb(p); 56 return tmp; 57 } 58 59 int main() 60 { 61 freopen("counttree.in","r",stdin); 62 freopen("counttree.out","w",stdout); 63 n=read(); 64 int sta; 65 for(int a,i=1;i<=n;i++) 66 { 67 a=read(); 68 if(!a) 69 sta=i; 70 else 71 AddEdge(a,i),AddEdge(i,a); 72 } 73 DFS(sta,-1); 74 for(int i=1;i<=n;i++) 75 { 76 printf("%d\n",Query(out[i])-Query(in[i]-1)); 77 Update(in[i],1); 78 } 79 fclose(stdin);fclose(stdout); 80 return 0; 81 }
2.COGS.1682. [HAOI2014]贴海报
思路:
看到这题就想起zhx讲过,当时好像是用并查集做的?然而题目数据范围1e7,没敢用(也不知怎么写==),就用的分块(其实也是暴力,然而写错了点,比暴力还低4分)。
正解:1.线段树:维护区间是否被染色:区间修改没被染色的点,标记,++ans;如果区间的点全被染过色,那ans不变。
2.浮水法:网上并不能搜到很多东西。一篇有关博客:http://www.cnblogs.com/SueMiller/archive/2011/08/05/2128794.html
代码:
1.线段树:时间:0.127s 内存使用:38.44MiB
1 #include<cmath> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 const int N=10000005,M=1005; 6 7 int n,m,Ans,A[M],B[M]; 8 bool flag,colored[N<<2]; 9 10 int read() 11 { 12 int now=0;char c=getchar(); 13 while(c<'0'||c>'9')c=getchar(); 14 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 15 return now; 16 } 17 18 void PushUp(int rt) 19 { 20 colored[rt]= colored[rt<<1]&&colored[rt<<1|1]; 21 } 22 23 /*void Build(int l,int r,int rt) 24 { 25 if(l==r) 26 return; 27 int m=(l+r)>>1; 28 Build(l,m,rt<<1); 29 Build(m+1,r,rt<<1|1); 30 PushUp(rt); 31 }*/ 32 33 void Modify(int l,int r,int rt,int L,int R) 34 { 35 if(colored[rt]) return; 36 if(L<=l && r<=R) 37 { 38 flag=1;colored[rt]=1; 39 return; 40 } 41 int m=(l+r)>>1; 42 if(L<=m) Modify(l,m,rt<<1,L,R); 43 if(m<R) Modify(m+1,r,rt<<1|1,L,R); 44 PushUp(rt); 45 } 46 47 int main() 48 { 49 freopen("ha14d.in","r",stdin); 50 freopen("ha14d.out","w",stdout); 51 n=read();m=read(); 52 // Build(1,n,1); 53 for(int i=1;i<=m;i++) 54 A[i]=read(),B[i]=read(); 55 for(int i=m;i>=1;i--) 56 { 57 flag=0; 58 Modify(1,n,1,A[i],B[i]); 59 if(flag) ++Ans; 60 } 61 printf("%d",Ans); 62 fclose(stdin);fclose(stdout); 63 return 0; 64 }/* 65 1000 12 66 1 100 67 50 80 68 80 99 69 50 98 70 1 56 71 100 200 72 200 300 73 300 500 74 500 600 75 600 1000 76 260 560 77 160 580 78 */
2.浮水法:时间:0.015s 内存使用:0.30MiB
1 #include<cstdio> 2 using namespace std; 3 const int N=10000005,M=1005; 4 5 int n,m,Ans,cur,A[M],B[M]; 6 bool vis[M]; 7 8 int read() 9 { 10 int now=0;char c=getchar(); 11 while(c<'0'||c>'9')c=getchar(); 12 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 13 return now; 14 } 15 16 void Solve(int a,int b,int now) 17 { 18 if(vis[cur]) return; 19 while(now<=m && (a>=B[now]||b<=A[now]))//需要等于 20 ++now; 21 if(now>m) 22 { 23 ++Ans,vis[cur]=1;//printf("%d:%d--%d\n",Ans,a,b); 24 return; 25 } 26 if(a<A[now] && A[now]<b) Solve(a,A[now],now+1);//不能等于 27 if(b>B[now] && B[now]>a) Solve(B[now],b,now+1); 28 } 29 30 int main() 31 { 32 // freopen("ha14d.in","r",stdin); 33 // freopen("ha14d.out","w",stdout); 34 n=read();m=read(); 35 for(int i=1;i<=m;i++) 36 A[i]=read(),B[i]=read(),++B[i];//右端点再加1,因为两端点是都不能放其他海报的(看不见) 37 for(cur=m-1;cur>=1;cur--) 38 Solve(A[cur],B[cur],cur+1); 39 printf("%d",++Ans); 40 // fclose(stdin);fclose(stdout); 41 return 0; 42 }
3.76分的分块(懒得纠正了)
1 #include<cmath> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 const int N=10000005,M=1005; 6 7 int n,m,Ans,Size,Blo[N],A[M],B[M]; 8 bool flag,colblo[10000],colored[N]; 9 10 int read() 11 { 12 int now=0;char c=getchar(); 13 while(c<'0'||c>'9')c=getchar(); 14 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 15 return now; 16 } 17 18 void Solve(int a,int b) 19 { 20 flag=0; 21 int ba=Blo[a],bb=Blo[b]; 22 if(!colblo[ba]) 23 for(int i=a;i<=min(a*Size,b);i++) 24 if(!colored[i]) 25 colored[i]=1,flag=1; 26 if(ba!=bb && !colblo[bb]) 27 for(int i=(bb-1)*Size+1;i<=b;i++) 28 if(!colored[i]) 29 colored[i]=1,flag=1; 30 for(int i=ba+1;i<=bb-1;i++) 31 if(!colblo[i])//当一些点把一整块覆盖时,无法有效判断. 32 colblo[i]=1,flag=1; 33 if(flag) ++Ans;//printf("l:%d r:%d\n",a,b); 34 } 35 36 int main() 37 { 38 // freopen("ha14d.in","r",stdin); 39 // freopen("ha14d.out","w",stdout); 40 n=read();m=read(); 41 Size=sqrt(n); 42 for(int i=1;i<=n;i++) 43 Blo[i]=(i-1)/Size+1; 44 for(int i=1;i<=m;i++) 45 A[i]=read(),B[i]=read(); 46 for(int i=m;i>=1;i--) 47 Solve(A[i],B[i]); 48 // printf("%d\n",Blo[n]); 49 // for(int i=1;i<=Blo[n];i++) 50 // printf("%d:All:%d\n",i,(int)colblo[i]); 51 printf("%d",Ans); 52 fclose(stdin);fclose(stdout); 53 return 0; 54 }
3.COGS.1619. [HEOI2012]采花
思路:
一眼就看出是个莫队,然而之前没看我不会写==。果断三分钟敲出暴力。
正解:1.学了莫队 用莫队写了一遍,过了==好简单。。5s限时可以的。
2.树状数组:
这题首先在线是没法做的,所以我们可以考虑离线算法
首先记录下每种颜色的下一种颜色所在的位置
将所有询问按照左端点进行排序
将所有颜色的第一个点x a[x]++
然后从左往右扫
扫到一个点x将a[next[x]]++
碰到一个询问l,r输出sum[r]-sum[l-1]
其中sum是a数组的前缀和
求前缀和可以用树状数组(是不是很眼熟,没错摘自黄学长博客)
代码:
1.莫队 时间:15.293s 内存使用:23.18MiB
1 #include<cmath> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 const int N=1000005; 6 7 int n,c,m,size,color[N],Times[N],now,ans[N]; 8 struct Ques 9 { 10 int l,r,id; 11 }q[N]; 12 13 int read() 14 { 15 int now=0;char c=getchar(); 16 while(c<'0'||c>'9')c=getchar(); 17 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 18 return now; 19 } 20 21 bool cmp(Ques a,Ques b) 22 {//左端点所在块为第一关键字,右端点为第二关键字 23 //if((a.l-1)/size+1 == (b.l-1)/size+1) return a.r < b.r; 24 if(a.l/size == b.l/size) return a.r < b.r; 25 return a.l/size < b.l/size; 26 } 27 28 inline void Add(int p) 29 { 30 ++Times[p]; 31 if(Times[p]==2) 32 ++now; 33 } 34 inline void Subd(int p) 35 { 36 --Times[p]; 37 if(Times[p]==1) 38 --now; 39 } 40 41 int main() 42 { 43 freopen("1flower.in","r",stdin); 44 freopen("1flower.out","w",stdout); 45 n=read();c=read();m=read(); 46 size=sqrt(n); 47 for(int i=1;i<=n;i++) 48 color[i]=read(); 49 for(int i=1;i<=m;i++) 50 q[i].l=read(),q[i].r=read(),q[i].id=i; 51 sort(q+1,q+1+m,cmp); 52 for(int i=1,l=1,r=0;i<=m;i++) 53 { 54 int ln=q[i].l,rn=q[i].r; 55 while(l>ln) 56 Add(color[--l]); 57 while(l<ln) 58 Subd(color[l++]); 59 while(r<rn) 60 Add(color[++r]); 61 while(r>rn) 62 Subd(color[r--]); 63 ans[q[i].id]=now; 64 } 65 for(int i=1;i<=m;i++) 66 printf("%d\n",ans[i]); 67 fclose(stdin);fclose(stdout); 68 return 0; 69 }
2018.2.26 Update:
+一些小优化
时间:10.803s 内存使用:16.89MiB
1 #include <cmath> 2 #include <cctype> 3 #include <cstdio> 4 #include <algorithm> 5 #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) 6 const int N=1e6+5,MAXIN=1e6; 7 8 int n,c,m,size,color[N],Times[N],now,ans[N]; 9 char IN[MAXIN],*SS=IN,*TT=IN; 10 struct Ques 11 { 12 int l,r,id; 13 bool operator <(const Ques &b)const{ 14 return l/size==b.l/size ? ((l/size)&1?r>b.r:r<b.r): l/size<b.l/size; 15 //左端点所在块为第一关键字,右端点为第二关键字 16 } 17 }q[N]; 18 19 inline int read() 20 { 21 int now=0;register char c=gc(); 22 for(;!isdigit(c);c=gc()); 23 for(;isdigit(c);now=now*10+c-'0',c=gc()); 24 return now; 25 } 26 inline void Add(int p){ 27 if(++Times[p]==2) ++now; 28 } 29 inline void Subd(int p){ 30 if(--Times[p]==1) --now; 31 } 32 33 int main() 34 { 35 freopen("1flower.in","r",stdin); 36 freopen("1flower.out","w",stdout); 37 38 n=read(),c=read(),m=read(),size=n/sqrt(m*2/3); 39 for(int i=1;i<=n;i++) color[i]=read(); 40 for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i; 41 std::sort(q+1,q+1+m); 42 for(int i=1,l=1,r=0;i<=m;i++) 43 { 44 int ln=q[i].l,rn=q[i].r; 45 while(l>ln) Add(color[--l]); 46 while(l<ln) Subd(color[l++]); 47 while(r<rn) Add(color[++r]); 48 while(r>rn) Subd(color[r--]); 49 ans[q[i].id]=now; 50 } 51 for(int i=1;i<=m;i++) printf("%d\n",ans[i]); 52 53 fclose(stdin);fclose(stdout); 54 return 0; 55 }
2.树状数组 时间:2.226s 内存使用:30.81MiB
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=1000005; 5 6 int n,c,m,color[N],Tree[N],Last[N],Next[N],Ans[N]; 7 struct Ques 8 { 9 int l,r,id; 10 bool operator <(const Ques &a)const 11 { 12 return l<a.l; 13 } 14 }q[N]; 15 16 int read() 17 { 18 int now=0;char c=getchar(); 19 while(c<'0'||c>'9')c=getchar(); 20 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 21 return now; 22 } 23 24 inline int lb(int x) 25 { 26 return x&(-x); 27 } 28 29 void Update(int p,int v) 30 { 31 while(p<=n) 32 Tree[p]+=v,p+=lb(p); 33 } 34 35 int Query(int p) 36 { 37 int tmp=0; 38 while(p) 39 tmp+=Tree[p],p-=lb(p); 40 return tmp; 41 } 42 43 int main() 44 { 45 // freopen("1flower.in","r",stdin); 46 // freopen("1flower.out","w",stdout); 47 n=read();c=read();m=read(); 48 for(int i=1;i<=n;i++) 49 color[i]=read(); 50 for(int i=n;i>0;i--) 51 Next[i]=Last[color[i]],Last[color[i]]=i; 52 for(int i=1;i<=c;i++) 53 if(Next[Last[i]])//颜色i第一个位置的下一个,即出现过2次,往后+1 54 Update(Next[Last[i]],1); 55 for(int i=1;i<=m;i++) 56 q[i].l=read(),q[i].r=read(),q[i].id=i; 57 sort(q+1,q+1+m); 58 for(int i=1,l=1;i<=m;i++) 59 { 60 while(l<q[i].l) 61 { 62 if(Next[l]) Update(Next[l],-1);//颜色i第一次出现的位置,往后-1(不算在内) 63 if(Next[Next[l]]) Update(Next[Next[l]],1);//颜色i第二次出现,往后+1 64 ++l; 65 } 66 Ans[q[i].id]=Query(q[i].r)-Query(q[i].l-1); 67 } 68 for(int i=1;i<=m;i++) 69 printf("%d\n",Ans[i]); 70 // fclose(stdin);fclose(stdout); 71 return 0; 72 }
20分的暴力
1 #include<cstdio> 2 using namespace std; 3 const int N=1000005; 4 5 int n,c,m,Ans,color[N],Times[N]; 6 bool vis[N]; 7 8 int read() 9 { 10 int now=0;char c=getchar(); 11 while(c<'0'||c>'9')c=getchar(); 12 while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar(); 13 return now; 14 } 15 16 int main() 17 { 18 freopen("1flower.in","r",stdin); 19 freopen("1flower.out","w",stdout); 20 n=read();c=read();m=read(); 21 for(int i=1;i<=n;i++) 22 color[i]=read(); 23 for(int i=1;i<=m;i++) 24 { 25 for(int j=1;j<=n;j++) 26 vis[j]=Times[j]=0; 27 Ans=0; 28 int l=read(),r=read(); 29 for(int j=l;j<=r;j++) 30 { 31 if(vis[color[j]])continue; 32 ++Times[color[j]]; 33 if(Times[color[j]]>1) 34 vis[color[j]]=1,++Ans; 35 } 36 printf("%d\n",Ans); 37 } 38 fclose(stdin);fclose(stdout); 39 return 0; 40 }
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------