HDU 3276 Graph and Queries [离线+并查集+treap]
2015-09-21 19:41
405 查看
题意:给出N个点以及其权值,M条边,30余万个操作(这里很坑,一开始数组笑了被坑的T到死);
操作1:将一开始图中某些边删除,如果已经删了就忽视此操作
操作2:将某个点的权值更改。
操作3:将某点联通的点集中第K大的数加到累加器。(注意K不保证对,又是一个坑点,没有特判我的程序跑了4500MS,卡过,判了1250MS......)
最后询问:累加器除以操作三的总数,保留6位小数。(小心操作三只有0个,要特判输出0,以及记得+CASE.....这里又WA到死)
范围:N<=2W , M<=6W 操作数小于40W
解法:操作从后往前遍历,查找第K大显然需要一个平衡树,并且此时的加边变成了合并操作,使用启发式合并可以N*LOGN*LOGN完成所有的合并,修改点值只需要在treap里删除并添加一个点,总的时间复杂度是(N*LOGN*LOGN+M*logN)
代码:
操作1:将一开始图中某些边删除,如果已经删了就忽视此操作
操作2:将某个点的权值更改。
操作3:将某点联通的点集中第K大的数加到累加器。(注意K不保证对,又是一个坑点,没有特判我的程序跑了4500MS,卡过,判了1250MS......)
最后询问:累加器除以操作三的总数,保留6位小数。(小心操作三只有0个,要特判输出0,以及记得+CASE.....这里又WA到死)
范围:N<=2W , M<=6W 操作数小于40W
解法:操作从后往前遍历,查找第K大显然需要一个平衡树,并且此时的加边变成了合并操作,使用启发式合并可以N*LOGN*LOGN完成所有的合并,修改点值只需要在treap里删除并添加一个点,总的时间复杂度是(N*LOGN*LOGN+M*logN)
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<iostream> #include<stdlib.h> #include<set> #include<map> #include<queue> #include<vector> #include<bitset> #pragma comment(linker, "/STACK:1024000000,1024000000") template <class T> bool scanff(T &ret){ //Faster Input char c; int sgn; T bit=0.1; if(c=getchar(),c==EOF) return 0; while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); if(c==' '||c=='\n'){ ret*=sgn; return 1; } while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10; ret*=sgn; return 1; } #define inf 1073741823 #define llinf 4611686018427387903LL #define PI acos(-1.0) #define lth (th<<1) #define rth (th<<1|1) #define rep(i,a,b) for(int i=a;i<=b;i++) #define drep(i,a,b) for(int i=a;i>=b;i--) #define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next) #define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++) #define mem(x,val) memset(x,val,sizeof(x)) #define mkp(a,b) make_pair(a,b) #define findx(x) lower_bound(b+1,b+1+bn,x)-b #define pb(x) push_back(x) using namespace std; typedef long long ll; typedef pair<int,int> pii; /************************************ orz学习计划: STATE: treap、splay -ing 替罪羊树 -wait 树链剖分 主席树 树套树 可持久化数据结构(论文) LC(论文) K-d Tree *************************************/ const int NN=400400; //TREAP int root[NN],tot; struct node{ int l,r,val,rnd,size; }t[NN*2]; void maintain(int x){ if(x>0)t[x].size=t[t[x].l].size+t[t[x].r].size+1; } void lturn(int &x){ int tmp=t[x].r; t[x].r=t[tmp].l; t[tmp].l=x; maintain(x); x=tmp; } void rturn(int &x){ int tmp=t[x].l; t[x].l=t[tmp].r; t[tmp].r=x; maintain(x); x=tmp; } void insert(int &x,int val){ //printf("~~~~>%d %d\n",x,val); if(x==0){ x=++tot; t[x].val=val; t[x].rnd=rand(); t[x].size=1; t[x].l=t[x].r=0; return; } if(val<t[x].val){ insert(t[x].l,val); if(t[t[x].l].rnd<t[x].rnd)rturn(x); } else { insert(t[x].r,val); if(t[t[x].r].rnd<t[x].rnd)lturn(x); } maintain(x); } void erase(int &x,int val){ if(val>t[x].val)erase(t[x].r,val); else if(val<t[x].val)erase(t[x].l,val); else{ if(t[x].l==0)x=t[x].r; else if(t[x].r==0)x=t[x].l; else{ if(t[t[x].l].rnd<t[t[x].r].rnd){ rturn(x); erase(t[x].r,val); } else{ lturn(x); erase(t[x].l,val); } } } maintain(x); } void merge(int &x,int &y){ insert(y,t[x].val); if(t[x].l)merge(t[x].l,y); if(t[x].r)merge(t[x].r,y); } int findk(int x,int val){ int lsz=t[t[x].l].size; if(lsz+1==val)return t[x].val; if(lsz+1>val)return findk(t[x].l,val); return findk(t[x].r,val-lsz-1); } void dfs(int x){ printf("-->%d val=%d \n",x,t[x].val); if(t[x].l)dfs(t[x].l); if(t[x].r)dfs(t[x].r); } //UNION FIND SET int f[NN],sz[NN]; int find(int x){ return (x==f[x])?x:find(f[x]=f[f[x]]); } void connec(int x,int y){ int i=find(x); int j=find(y); if(i==j)return; if(sz[i]>sz[j])swap(i,j); sz[j]+=sz[i]; f[i]=j; merge(root[i],root[j]); } //INIT int n,m,a[NN],qn; struct edge{ int x,y; }ed[NN]; struct query{ int op,x,y; }q[NN]; bool vis[NN]; void init(){ char s[5]; rep(i,1,n)scanf("%d",&a[i]); rep(i,1,m)scanf("%d%d",&ed[i].x,&ed[i].y),vis[i]=1; qn=0; while(scanf("%s",s)){ if(s[0]=='E')break; if(s[0]=='D'){ q[++qn].op=1,scanf("%d",&q[qn].x); if(!vis[q[qn].x])qn--; vis[q[qn].x]=0; } if(s[0]=='Q')q[++qn].op=2,scanf("%d%d",&q[qn].x,&q[qn].y); if(s[0]=='C'){ q[++qn].op=3; int idx; scanf("%d",&idx); q[qn].x=idx; q[qn].y=a[idx]; scanf("%d",&a[idx]); } } rep(i,1,n)f[i]=i,sz[i]=1; rep(i,1,n){ t[i].val=a[i]; t[i].rnd=rand(); t[i].size=1; t[i].l=t[i].r=0; root[i]=i; } tot=n; } void modify(int x,int val){ int i=find(x); erase(root[i],a[x]); a[x]=val; insert(root[i],val); } int main(){ int cas=0; while(scanf("%d%d",&n,&m)!=EOF){ cas++; if(n==0&&m==0)break; init(); rep(i,1,m)if(vis[i])connec(ed[i].x,ed[i].y); double ans=0.0; int cot=0; drep(i,qn,1){ if(q[i].op==1){ connec(ed[q[i].x].x,ed[q[i].x].y); } if(q[i].op==2){ cot++; int x=q[i].x; int y=q[i].y; x=find(x); if(y>sz[x]||y<=0)continue; ans+=double(findk(root[x],sz[x]-(y-1))); } if(q[i].op==3){ modify(q[i].x,q[i].y); } } printf("Case %d: ",cas); if(cot==0)printf("%.6f\n",ans); else printf("%.6f\n",ans/double(cot)); } return 0; }
相关文章推荐
- block回调中调用方法的UI更新问题
- IOS 不同的 UIViewController 之间如何跳转
- iOS8下,UIAlertController内存泄露怎么办?
- MVC 用EasyUI
- UI_UIScrollView
- iOS UICollectionView
- UI06_无限滚动的相册
- UI06_UIScrollView
- UI05_手势
- UI05_Control
- UI04_delegate
- UI04_Target-Action
- CALayer的常用属性(笔记与分享)
- UI_Touch
- mapreduce中的sequenceFile类,MapFile解析
- UINavigationController (导航控制器)
- UIWindow & UIWindowLevel笔记
- 励精图治---Concurrency---GUI设计
- UItableView一些小方法
- poj3581 Sequence(后缀数组sa的运用+离散化)