您的位置:首页 > 其它

UVALive 5031

2015-08-06 10:48 405 查看
<span style="font-family: SimHei;">#include<cstdio></span>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;//题目说每种询问20万,总共60万,开小了RE
const int MAXN=20005,MAXM=60005,MAXQ=600001,MAXNODE=MAXQ*2;
int val[MAXNODE],r[MAXNODE],w[MAXM],u[MAXM],v[MAXM],ch[MAXNODE][2],fa[MAXN];
int size[MAXNODE],root[MAXNODE],vis[MAXM],n,m;
long long ans=0;int cnt=0;
queue<int> que;
struct Query
{
char c;int a,b;
Query(char c=0,int a=0,int b=0):c(c),a(a),b(b){}
void init(){c=0;a=0;b=0;}
}c[MAXQ];
void Read(int &x)
{
x=0;char c;int flag=0,si=1;
while(c=getchar())
{
if(c=='-')si=-1;
if(c>='0'&&c<='9')
x*=10,x+=c-'0',flag=1;
else if(flag) break;
}
x*=si;
}
void init()
{
memset(vis,0,sizeof(vis));
memset(size,0,sizeof(size));
for(int i=1;i<=MAXQ;i++)c[i].init();//这里没有清空结构体导致多组数据WA
memset(ch,0,sizeof(ch));
for(int i=1;i<=n;i++)
Read(w[i]);
for(int i=1;i<=m;i++)
Read(u[i]),Read(v[i]);
for(int i=1;i<=n;i++)fa[i]=i;
while(!que.empty())que.pop();
for(int i=1;i<MAXNODE;i++)que.push(i);
}
int newnode(int vv)
{
int sz=que.front();que.pop();
val[sz]=vv;r[sz]=rand();size[sz]=1;
return  sz;
}
int cmp(int a,int b)//我本来写的是bool,sort写多了。。。导致返回-1的时候直接返回1
{
if(b==val[a])return -1;
return b<val[a]?0:1;
}
void maintain(int x)
{
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void rotate(int &o,int d)
{
int k=ch[o][d^1];ch[o][d^1]=ch[k][d];ch[k][d]=o;//这里d直接用1,0代替了
maintain(o),maintain(k);o=k;
}
void del(int &x)
{
que.push(x);x=0;
}
void insert(int &o,int x)
{
if(!o){o=newnode(x);return ;}
int d=x<val[o]?0:1;
insert(ch[o][d],x);
if(r[o]<r[ch[o][d]])rotate(o,d^1);
maintain(o);
}
void remove(int &o,int x)
{
int d=cmp(o,x);
if(d==-1)
{
if(ch[o][0]==0)o=ch[o][1];
else if(ch[o][1]==0)o=ch[o][0];
else{
int d2=r[ch[o][0]]>r[ch[o][1]]?1:0;
rotate(o,d2);remove(ch[o][d2],x);
}
}
else remove(ch[o][d],x);
if(o)maintain(o);//并没有maintain
}
int getFa(int x)
{
return fa[x]==x?x:fa[x]=getFa(fa[x]);
}
void merge(int &a,int &b)
{
if(ch[a][0])merge(ch[a][0],b);
if(ch[a][1])merge(ch[a][1],b);
insert(b,val[a]);del(a);
}
int kth(int &o,int x)
{
if(x>size[o]||!o||x<=0)return 0;
int num=size[ch[o][1]];
if(num+1==x)return val[o];
if(x<=num)return kth(ch[o][1],x);
else return kth(ch[o][0],x-num-1);//num,x写反了导致出了负数
}
void chang(int x,int y)
{
int u=getFa(x);
remove(root[u],w[x]);
insert(root[u],w[x]=y);
}
void addEge(int i)
{
int f1=getFa(u[i]),f2=getFa(v[i]);
if(f1==f2)return;
if(size[f1]>size[f2])swap(f1,f2);
fa[f1]=f2;
merge(root[f1],root[f2]);
}
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
int kase=0;
while(1)
{
Read(n);Read(m);
if(n==0&&m==0)break;
init();
int q=1,cnt=0;
char C;
int x,y;long long ans=0;
while(1)
{
scanf("%c",&C);
if(C=='E')break;
if(C=='Q') Read(x),Read(y);
else if(C=='D') Read(x),y=0,vis[x]=1;
else if(C=='C')Read(x),y=w[x],Read(w[x]);//这里没有倒着存
if(C=='D'||C=='Q'||C=='C')c[q++]=Query(C,x,y);
}
for(int i=1;i<=n;i++)
root[i]=newnode(w[i]);
for(int i=1;i<=m;i++)
if(!vis[i])addEge(i);
while(q>=1)
{
C=c[q].c;x=c[q].a;y=c[q].b;
if(C=='D')addEge(x);
else if(C=='C')chang(x,y);
else if(C=='Q')ans+=(long long)kth(root[getFa(x)],y),cnt++;
q--;
}
printf("Case %d: %.6lf\n",++kase,(double)ans/cnt);
}
}


这是我们联赛模拟的第三题,我打了个暴力,然而出题人的数据根本不给暴力留活路,无奈看着std然后打了个treap。

给定一张无向图,有三个操作:删除一条边,修改一个点的权值,查询一个点所在联通块的K大值。。这题可以设计一个离线的算法,也就是说先把所有操作读进来,然后删除掉的边标记一下,建成最终的图(其实并不需要真正建图,用并查集维护联通性即可),最后反着做,也就是加边。我们给每一个联通块建一treap,记一个root维护每个点所在treap的根结点的编号(这个编号是树上节点编号,不是输入的图节点的编号)修改权值就删除这个,再插入这个,我当时没想到修改也要倒着来,也就是说w数组应该保存最后的修改后的权值,修改权值时再一步一步改回,于是光荣WA了,调了好久。加边的话实际上就是合并两个treap,我们采用启发式合并,即size小的往size大的一个一个暴力插入,每次合并,任意一个需要插入的点所在树的size至少会加倍。由于树的节点不超过n,任意节点至多插logn次,每次插要logn,因此总时间复杂度是O(nlog^2
n)的,实际上应该快得多。

然后就是放代码了,代码里有我WA过的地方。

%%%__debug大神打splay三百多行。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: