NOIp 0910 爆零记
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIp 0910 爆零记相关的知识,希望对你有一定的参考价值。
这套题是神犇chty出的。
刚拿到题的时候有点懵逼,因为按照一般的套路第一题都是一眼题,但是看到第一题后想了很多个算法和数据结构好像都不能很好的解决。然后就随手敲了个暴力去看T2。
嗯...文件名是bag这道题还真就是bag,听说是分组背包?背包现在我也就会个0/1了,所以怒上并查集优化相对关系。顺利AC

1 //T2 2 //by Cydiater 3 //2016.9.10 4 #include <iostream> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cmath> 8 #include <queue> 9 #include <map> 10 #include <cstring> 11 #include <string> 12 #include <algorithm> 13 #include <queue> 14 #include <iomanip> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 #define FILE "bag" 20 const int MAXN=1e3+5; 21 const int oo=0x3f3f3f3f; 22 inline int read(){ 23 char ch=getchar();int x=0,f=1; 24 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 25 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 26 return x*f; 27 } 28 int N,M,K,f[MAXN],head,tail,ans[MAXN*100],Ans=0,q[MAXN]; 29 struct _data{ 30 int v,group_id,w; 31 }a[MAXN]; 32 namespace solution{ 33 int getf(int k){ 34 if(f[k]==k)return k; 35 f[k]=getf(f[k]); 36 return f[k]; 37 } 38 inline void merge(int x,int y){f[getf(x)]=getf(y);} 39 inline bool cmp(_data x,_data y){return x.group_id<y.group_id;} 40 void init(){ 41 N=read();M=read();K=read(); 42 up(i,1,N){ 43 a[i].v=read(); 44 a[i].w=read(); 45 f[i]=i; 46 } 47 up(i,1,K){ 48 int x=read(),y=read(); 49 merge(x,y); 50 } 51 up(i,1,N)a[i].group_id=getf(i); 52 sort(a+1,a+N+1,cmp); 53 } 54 void DP(){ 55 a[0].group_id=0; 56 up(i,1,N){ 57 if(a[i].group_id!=a[i-1].group_id){ 58 head=1;tail=0;q[++tail]=i++; 59 while(a[i].group_id==a[i-1].group_id)q[++tail]=i++;i--; 60 } 61 down(k,M,0)up(j,head,tail){ 62 int id=q[j]; 63 if(a[id].w+k<=M){ 64 ans[a[id].w+k]=max(ans[a[id].w+k],ans[k]+a[id].v); 65 Ans=max(Ans,ans[a[id].w+k]); 66 } 67 } 68 } 69 } 70 void output(){ 71 cout<<Ans<<endl; 72 } 73 } 74 int main(){ 75 freopen(FILE".in","r",stdin); 76 freopen(FILE".out","w",stdout); 77 //freopen("input.in","r",stdin); 78 using namespace solution; 79 init(); 80 DP(); 81 output(); 82 return 0; 83 }
然后扭过头去看T1了...看着题,开始想怎么优化线段树..想了五分钟,弃疗。正准备去看第三题,忽然想到貌似这个是莫队的模板题。敲了一下,不是很放心,拍了半小时,好像没什么问题。就交了。

1 //test for bat 2 //by Cydiater 3 //2016.9.10 4 #include <iostream> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cstring> 8 #include <string> 9 #include <algorithm> 10 #include <queue> 11 #include <map> 12 #include <iomanip> 13 #include <cmath> 14 #include <ctime> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 #define FILE "tower" 20 const int MAXN=1e6+5; 21 const int oo=0x3f3f3f3f; 22 inline int read(){ 23 char ch=getchar();int x=0,f=1; 24 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 25 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 26 return x*f; 27 } 28 int N,M,a[MAXN],btBlock[MAXN],tmp,Count[MAXN],ans=0,head,tail; 29 struct Query{ 30 int x,y,id,ans; 31 }q[MAXN]; 32 namespace solution{//vio makes different 33 inline bool cmp(Query x,Query y){return btBlock[x.y]==btBlock[y.y]?x.x<y.x:btBlock[x.y]<btBlock[y.y];} 34 inline bool re_cmp(Query x,Query y){return x.id<y.id;} 35 void init(){ 36 N=read();M=read(); 37 up(i,1,N)a[i]=read(); 38 up(i,1,M){ 39 int x=read(),y=read(); 40 if(y<x)swap(x,y); 41 q[i].x=x;q[i].y=y;q[i].id=i; 42 } 43 tmp=sqrt(1.0*N); 44 up(i,1,N)btBlock[i]=(i/tmp)+1; 45 sort(q+1,q+M+1,cmp); 46 } 47 void push(int id,int tag){ 48 Count[a[id]]+=tag; 49 if(tag==1&&Count[a[id]]==1)ans++; 50 if(tag==-1&&Count[a[id]]==0)ans--; 51 } 52 void MosAlg(){ 53 memset(Count,0,sizeof(Count)); 54 head=1;tail=0; 55 up(k,1,M){ 56 int x=q[k].x,y=q[k].y; 57 while(tail<y)push(++tail,1); 58 while(tail>y)push(tail--,-1); 59 while(head<x)push(head++,-1); 60 while(head>x)push(--head,1); 61 q[k].ans=ans; 62 } 63 } 64 void output(){ 65 sort(q+1,q+M+1,re_cmp); 66 up(i,1,M)printf("%d\\n",q[i].ans); 67 //cout<<"Time has passed"<<1.0*clock()/1000<<"s!"<<endl; 68 } 69 } 70 int main(){ 71 //freopen("input.in","r",stdin); 72 //freopen("out1.out","w",stdout); 73 freopen(FILE".in","r",stdin); 74 freopen(FILE".out","w",stdout); 75 using namespace solution; 76 init(); 77 MosAlg(); 78 output(); 79 return 0; 80 }
然后考完试后有人给我说把所有可能的询问存下来就行了= =....我还能说些什么
然后就去看喜闻乐见的T3了。
一眼贪心,然后就很快速的想到了$O(NM)$的算法。这个$N$后的$M$是可优化的,其本质就是查找一个动态集合里$num$的后继,这不就是treap吗?
但是思考具体实现好像出了些问题,因为我的贪心排序是递增排序(实际上应该是递减排序,递减排序的话也就没有了下面所说的麻烦),而递增排序的话每次访问过的节点必定是$id$以后的节点,这就很不优雅了,我需要维护一个$node$和$v$的关系。
然后$v$还可以重复...
exm?
思考了半天怎么防止区间重复的删除,到了11:20,弃疗,敲暴力。
然后暴力就敲崩了。
这个是最后改好的:

1 //OJ 1939 2 //by Cydiater 3 //2016.9.10 4 #include <iostream> 5 #include <cstdio> 6 #include <cstring> 7 #include <string> 8 #include <algorithm> 9 #include <queue> 10 #include <map> 11 #include <ctime> 12 #include <cmath> 13 #include <string> 14 #include <iomanip> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 const ll MAXN=1e6+5; 20 const ll oo=0x3f3f3f3f; 21 inline ll read(){ 22 char ch=getchar();ll x=0,f=1; 23 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 24 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 25 return x*f; 26 } 27 int N,M,root=0,tol=0,tmp; 28 ll ans=0; 29 struct _data{ 30 int x,y; 31 }a[MAXN],b[MAXN]; 32 struct tree{ 33 int leftt,rightt,v,siz,cnt,rnd; 34 }t[MAXN]; 35 namespace solution{ 36 inline bool cmpfory(_data x,_data y){return x.y>y.y;} 37 inline void updata(int k){t[k].siz=t[t[k].leftt].siz+t[t[k].rightt].siz+t[k].cnt;} 38 void init(){ 39 N=read();M=read(); 40 up(i,1,N){ 41 a[i].x=read();a[i].y=read(); 42 } 43 up(i,1,M){ 44 b[i].x=read();b[i].y=read(); 45 } 46 sort(a+1,a+N+1,cmpfory); 47 sort(b+1,b+M+1,cmpfory); 48 } 49 void lefturn(int &k){ 50 int tt=t[k].rightt;t[k].rightt=t[tt].leftt;t[tt].leftt=k; 51 t[tt].siz=t[k].siz;updata(k);k=tt; 52 } 53 void righturn(int &k){ 54 int tt=t[k].leftt;t[k].leftt=t[tt].rightt;t[tt].rightt=k; 55 t[tt].siz=t[k].siz;updata(k);k=tt; 56 } 57 void insert(int &k,int v){ 58 if(k==0){ 59 k=++tol;t[k].leftt=t[k].rightt=0; 60 t[k].rnd=rand();t[k].v=v;t[k].siz=t[k].cnt=1; 61 return; 62 } 63 t[k].siz++; 64 if(t[k].v==v){ 65 t[k].cnt++; 66 return; 67 } 68 if(v<t[k].v){ 69 insert(t[k].leftt,v); 70 if(t[k].rnd>t[t[k].leftt].rnd)righturn(k); 71 }else if(v>t[k].v){ 72 insert(t[k].rightt,v); 73 if(t[k].rnd>t[t[k].rightt].rnd)lefturn(k); 74 } 75 } 76 void nxt(int k,int v){ 77 if(k==0)return; 78 if(t[k].v>=v){ 79 tmp=t[k].v; 80 nxt(t[k].leftt,v); 81 }else nxt(t[k].rightt,v); 82 } 83 void del(int &k,int v){ 84 if(root==0)return; 85 if(v==t[k].v){ 86 if(t[k].cnt>1){ 87 t[k].cnt--; 88 t[k].siz--; 89 return; 90 } 91 if(t[k].leftt*t[k].rightt==0){ 92 k=t[k].leftt+t[k].rightt; 93 return; 94 } 95 if(t[t[k].leftt].rnd<t[t[k].rightt].rnd){ 96 righturn(k); 97 del(k,v); 98 }else{ 99 lefturn(k); 100 del(k,v); 101 } 102 } 103 else if(v<t[k].v){ 104 t[k].siz--; 105 del(t[k].leftt,v); 106 }else{ 107 t[k].siz--; 108 del(t[k].rightt,v); 109 } 110 } 111 void slove(){ 112 int j=1; 113 up(i,1,N){ 114 while(b[j].y>=a[i].y&&j<=M) 115 insert(root,b[j++].x); 116 tmp=-1; 117 nxt(root,a[i].x);ans+=tmp; 118 if(tmp==-1){ 119 puts("-1"); 120 exit(0); 121 } 122 del(root,tmp); 123 } 124 } 125 void output(){ 126 cout<<ans<<endl; 127 } 128 } 129 int main(){ 130 //freopen("input.in","r",stdin); 131 using namespace solution; 132 init(); 133 slove(); 134 output(); 135 return 0; 136 }
最后$100+100+0$滚粗。
小结:
还是应该提高自己的姿势水平,贪心这种东西太玄了。而且比赛也要多打,思路要放宽。对我们来说NOIp比的实际上已经是谁能AK了。
以上是关于NOIp 0910 爆零记的主要内容,如果未能解决你的问题,请参考以下文章