http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=340
A Alice's present 题意:给出一个10^5 的数组,5w次询问,每次询问给出一段区间 [ l ,r ] 要求判断区间里的每个数是否只是出现了一次,如果是输出OK,否则输出从右 向左第一个出现两次的数
思路: 我是用线段树离线查询做的,感觉单调栈也可以做得样子,而且代码应该短很多
#include <cstdlib> #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define inf 0x3fffffff const int maxn=500010; int d[maxn<<2],first[maxn],a[maxn],tab[maxn]; struct Node { int l,r,id; }q[50010]; int cmp(Node a,Node b) { return a.l > b.l; } void build(int l,int r,int rt) { d[rt]=inf; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int p,int val,int l,int r,int rt) { if(l==r){ d[rt]=val;return; } int m=(l+r)>>1; if(p<=m) update(p,val,lson); else update(p,val,rson); d[rt]=min(d[rt<<1],d[rt<<1|1]); } int query(int L,int R,int val,int l,int r,int rt) { if(d[rt]>val) return -1; if(l==r) return l; int m=(l+r)>>1; if(R<=m) return query(L,R,val,lson); if(L>m) return query(L,R,val,rson); int ret2=query(m+1,R,val,rson); if(ret2!=-1) return ret2; return query(L,m,val,lson);; } int bin(int key,int l,int r) { while(l<=r) { int m=(l+r)>>1; if(tab[m]==key) return m; else if(tab[m]>key) r=m-1; else l=m+1; } } int ans[maxn]; int main() { int n,m; while(scanf("%d",&n)==1) { build(1,n,1); for(int i=1;i<=n;i++) scanf("%d",&a[i]),tab[i-1]=a[i]; sort(tab,tab+n); int k=unique(tab,tab+n)-tab-1; scanf("%d",&m); for(int i=0;i<m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i; sort(q,q+m,cmp); memset(first,-1,sizeof(first)); int dd=0; for(int i=n;i>=1;i--) { int pos=bin(a[i],0,k); //cout<<a[i]<<" "<<pos<<endl; if(first[pos]==-1) first[pos]=i; else update(i,first[pos],1,n,1),first[pos]=i; while(dd<m&&q[dd].l==i) { //cout<<q[dd].l<<" "<<q[dd].r<<" "; int p=query(q[dd].l,q[dd].r,q[dd].r,1,n,1); ans[q[dd].id]= (p==-1)?-1:a[p]; dd++; } if(dd>=m) break; } for(int i=0;i<m;i++) if(ans[i]!=-1) printf("%d\n",ans[i]); else puts("OK"); puts(""); } return 0; }
C Cinema in Akiba 题, 线段树水题,因为输出错误害了我wa两次,无语……
#include <cstdlib> #include <iostream> #include <cstring> #include <cstdio> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=500010; int d[maxn<<2]; void build(int l,int r,int rt) { d[rt]=r-l+1; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } int update(int p,int l,int r,int rt) { if(l==r){ d[rt]=0;return l; } int m=(l+r)>>1,ret; if(p<=d[rt<<1]) ret=update(p,lson); else ret=update(p-d[rt<<1],rson); d[rt]=d[rt<<1]+d[rt<<1|1]; return ret; } int ans[maxn]; int main() { int n,m,a; while(scanf("%d",&n)==1) { build(1,n,1); for(int i=1;i<=n;i++) { scanf("%d",&a); ans[i]=update(a,1,n,1); //cout<<ans[i]<<endl; } scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%d",&a); if(i)putchar(' '); printf("%d",ans[a]); } puts(""); } return 0; }
思路: 我是用并查集做的,每个孩子都有一个集合表示该孩子知道的信息量,但是信息的种类最多是1000,孩子个数是10w,直接开数组的是开不下的,所以我用到STL的容器,把每个不是根节点的内存及时的销毁……其他的就是并查集的找父亲节点和合并两个集合就可以了
#include <cstdlib> #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <map> using namespace std; const int maxn=100010; int fa[maxn]; vector<int> set[maxn]; map<string,int> mp; bool flag[maxn]; int find(int a) { while(fa[a]!=-1) a=fa[a]; return a; } void Union(int u,int v) { int f1=find(u),f2=find(v); if(f1==f2) return; int sz=set[f2].size(); for(int i=0;i<sz;i++) set[f1].push_back(set[f2][i]); sort(set[f1].begin(),set[f1].end()); set[f1].resize(unique(set[f1].begin(),set[f1].end())-set[f1].begin()); set[f2].clear(); fa[f2]=f1; } int main() { int n,m,k,a,dd; char ord[20],name1[20],name2[20]; while(scanf("%d",&n)==1) { dd=1; memset(fa,-1,sizeof(fa)); for(int i=0;i<n;i++) { scanf("%s",ord); if(ord[0]=='a') { scanf("%s",name1); scanf("%d",&k); mp[name1]=dd; set[dd].clear(); for(int j=1;j<=k;j++) scanf("%d",&a),set[dd].push_back(a); dd++; } else if(ord[0]=='s') { scanf("%s %s",name1,name2); int u=mp[name1],v=mp[name2]; Union(u,v); } else { scanf("%s",name1); int f1=find(mp[name1]); printf("%d\n",set[f1].size()); } } mp.clear(); } return 0; } /* 8 arrive FatSheep 3 4 7 5 arrive riversouther 2 4 1 share FatSheep riversouther check FatSheep arrive delta 2 10 4 check delta share delta FatSheep check riversouther */
Just Another Information Sharing Problem |
tick 就是 还要把m每个知道的信息 要和源点建流量为1的边,不然会wa。 代码太戳,就不贴了
K题 Keep Deleting 做得比较爽的一题,30分钟1Y。 思路就是kmp,然后建一个栈,栈里放着没有被删除的字符,从左向右扫描
#include <cstdlib> #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn=555555; char s[maxn],a[300],stack[maxn]; int next[300],len; void get_next() { next[0]=-1; int i=0,j=-1; while(i<len) { if(j==-1||a[i]==a[j]) next[++i]=++j; else j=next[j]; } } int local(int top,char c) { if(top==0) return (s[0]==c)?0:-1; int i=stack[top-1]+1; while(i!=-1&&a[i]!=c) i=next[i]; return i; } int solve() { int L=strlen(s),top=0,ret=0; for(int i=0;i<L;i++) { int pos=local(top,s[i]); if(pos>=len-1) top-=(len-1),ret++; else stack[top++]=pos; //cout<<s[i]<<" "<<top<<": "<<pos<<endl; } return ret; } int main(int argc, char *argv[]) { while(scanf("%s%s",a,s)==2) { len=strlen(a); get_next(); /* for(int i=0;i<len;i++) cout<<next[i]<<" "; cout<<endl;*/ printf("%d\n",solve()); } return 0; }