http://www.elijahqi.win/2018/02/25/hdu3726/
Problem Description
You are given an undirected graph with N vertexes and M edges. Every vertex in this graph has an integer value assigned to it at the beginning. You’re also given a sequence of operations and you need to process them as requested. Here’s a list of the possible operations that you might encounter:
1) Deletes an edge from the graph.
The format is [D X], where X is an integer from 1 to M, indicating the ID of the edge that you should delete. It is guaranteed that no edge will be deleted more than once.
2) Queries the weight of the vertex with K-th maximum value among all vertexes currently connected with vertex X (including X itself).
The format is [Q X K], where X is an integer from 1 to N, indicating the id of the vertex, and you may assume that K will always fit into a 32-bit signed integer. In case K is illegal, the value for that query will be considered as undefined, and you should return 0 as the answer to that query.
3) Changes the weight of a vertex.
The format is [C X V], where X is an integer from 1 to N, and V is an integer within the range [-106, 106].
The operations end with one single character, E, which indicates that the current case has ended.
For simplicity, you only need to output one real number - the average answer of all queries.
Input
There are multiple test cases in the input file. Each case starts with two integers N and M (1 <= N <= 2 * 104, 0 <= M <= 6 * 104), the number of vertexes in the graph. The next N lines describes the initial weight of each vertex (-106 <= weight[i] <= 106). The next part of each test case describes the edges in the graph at the beginning. Vertexes are numbered from 1 to N. The last part of each test case describes the operations to be performed on the graph. It is guaranteed that the number of query operations [Q X K] in each case will be in the range [1, 2 * 105], and there will be no more than 2 * 105 operations that change the values of the vertexes [C X V].
There will be a blank line between two successive cases. A case with N = 0, M = 0 indicates the end of the input file and this case should not be processed by your program.
Output
For each test case, output one real number – the average answer of all queries, in the format as indicated in the sample output. Please note that the result is rounded to six decimal places.
Sample Input
3 3 10 20 30 1 2 2 3 1 3 D 3 Q 1 2 Q 2 1 D 2 Q 3 2 C 1 50 Q 1 1 E 3 3 10 20 20 1 2 2 3 1 3 Q 1 1 Q 1 2 Q 1 3 E 0 0
Sample Output
Case 1: 25.000000 Case 2: 16.666667
Hint
For the first sample: D 3 – deletes the 3rd edge in the graph (the remaining edges are (1, 2) and (2, 3)) Q 1 2 – finds the vertex with the second largest value among all vertexes connected with 1. The answer is 20. Q 2 1 – finds the vertex with the largest value among all vertexes connected with 2. The answer is 30. D 2 – deletes the 2nd edge in the graph (the only edge left after this operation is (1, 2)) Q 3 2 – finds the vertex with the second largest value among all vertexes connected with 3. The answer is 0 (Undefined). C 1 50 – changes the value of vertex 1 to 50. Q 1 1 – finds the vertex with the largest value among all vertex connected with 1. The answer is 50. E – This is the end of the current test case. Four queries have been evaluated, and the answer to this case is (20 + 30 + 0 + 50) / 4 = 25.000. For the second sample, caution about the vertex with same weight: Q 1 1 – the answer is 20 Q 1 2 – the answer is 20 Q 1 3 – the answer is 10
重新拍了下小数据 找到了错误 wc原来改原来的写法的时候误删了判断在统一集合
orz给icefox跪了 为什么写的这么快调试这么快
一开始看题 直接离线 星球大战 倒着做Okay 开始码一小时左右过样例 然后hdu死活tle 对拍5000左右的数据一天没查错 对拍10000左右就挂了 似乎数组不够大了 不会算启发式合并内存池需要多少 因为没有算内存 每次直接暴力往里面插入
那么后来膜icefox巨佬代码 发现可以我把每个点当作splay的下标 其他操作就是splay的基本操作 离线是为了将分离变成合并 Okay 到此结束
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 66000
#define M 66000
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
int x,y;
}data[M];
struct node1{
int id,x,k;
}qr[500000];
int v[N],size[N],fa[N],c[N][2],fa1[N],q[N],n,m,num,rt[N],w[N];
bool visit[M];
inline void update(int x){
size[x]=size[c[x][0]]+size[c[x][1]]+1;
}
inline void rotate(int x,int &tar){
int y=fa[x],z=fa[y];
if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
int l=c[y][1]==x,r=l^1;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
while(x!=tar){
int y=fa[x],z=fa[y];
if (y!=tar){
if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
}rotate(x,tar);
}
}
inline void insert1(int &x,int xx,int f,int id){
if (!x){x=xx;size[x]=1;fa[x]=f;splay(x,rt[id]);return;}
if (v[xx]<v[x]) insert1(c[x][0],xx,x,id);else insert1(c[x][1],xx,x,id);
}
inline int find(int x,int p){
int l=c[x][0],r=c[x][1];
if(size[l]+1==p) return x;
if (p<=size[l]) return find(l,p);else return find(r,p-size[l]-1);
}
inline int find1(int x){
while(x!=fa1[x]) x=fa1[x]=fa1[fa1[x]];return x;
}
inline void ins(int x,int y){
fa1[x]=y;int l=1,r=0;q[++r]=rt[x];
while(l<=r){
int now=q[l++];
if (c[now][0]) q[++r]=c[now][0];
if (c[now][1]) q[++r]=c[now][1];
}int xx;
for (int i=1;i<=r;++i)
if (v[q[i]]!=-inf&&v[q[i]]!=inf)
xx=q[i],fa[xx]=c[xx][0]=c[xx][1]=0,insert1(rt[y],xx,rt[y],y);
}
inline void del(int &x,int p){
splay(p,x);int succ=c[x][1],pre=c[x][0];
while(c[pre][1]) pre=c[pre][1];
while(c[succ][0]) succ=c[succ][0];
splay(succ,x);splay(pre,c[x][0]);c[pre][1]=0;update(pre);update(x);
}
inline int init(int x){v[++num]=x;size[num]=1;c[num][0]=c[num][1]=0;return num;}
int main(){
freopen("hdu3726.in","r",stdin);
freopen("hdu3726.out","w",stdout);
int test=0;
while((n=read())&&(m=read())){++test;
for (int i=1;i<=n;++i) v[i]=read();num=n;
for (int i=1;i<=m;++i) data[i].x=read(),data[i].y=read();
memset(visit,0,sizeof(visit));int tot=0,cnt=0;
while(1){
char ch=gc();while(ch!='D'&&ch!='Q'&&ch!='C'&&ch!='E') ch=gc();
if (ch=='E') break;
if (ch=='D'){qr[++tot].id=1;qr[tot].x=read();visit[qr[tot].x]=1;}
if (ch=='Q'){qr[++tot].id=2;qr[tot].x=read();qr[tot].k=read();}
if (ch=='C'){qr[++tot].id=3;qr[tot].x=read();qr[tot].k=v[qr[tot].x];v[qr[tot].x]=read();}
}double ans=0;for (int i=1;i<=n;++i) fa1[i]=rt[i]=i,size[i]=1,c[i][1]=c[i][0]=fa[i]=0;
for (int i=1;i<=n;++i) insert1(rt[i],init(-inf),rt[i],i),insert1(rt[i],init(inf),rt[i],i);
for (int i=1;i<=m;++i){
if (visit[i]) continue;int x=find1(data[i].x),y=find1(data[i].y);
if (x==y) continue;if (size[rt[x]]>size[rt[y]]) ins(y,x);else ins(x,y);
}
for (int i=tot;i;--i){
if (qr[i].id==1){
int id=qr[i].x,x=data[id].x,y=data[id].y;
x=find1(x),y=find1(y);if (x==y) continue;
if(size[rt[x]]>size[rt[y]]) ins(y,x);else ins(x,y);
}
if (qr[i].id==2){
int x=find1(qr[i].x),k=qr[i].k;++cnt;if (size[rt[x]]<k+2||k<=0) continue;
k=size[rt[x]]-k;ans+=v[find(rt[x],k)];
}
if (qr[i].id==3){
int x=find1(qr[i].x),k=qr[i].k;
del(rt[x],qr[i].x);v[qr[i].x]=k;
insert1(rt[x],qr[i].x,rt[x],x);
}
}printf("Case %d: %.6lf\n",test,ans/cnt);
}
return 0;
}
附对拍代码
#include<cstdio>
#include<iostream>
#include<ctime>
#include<map>
#include<cstdlib>
#include<algorithm>
using namespace std;
int a[30000+20];
struct nod
{
int id,d;
}d[30000+20];
bool cmpid(nod x,nod y)//按编号排序
{
return x.id<y.id;
}
bool cmp(nod x,nod y)//按度数排序
{
if(x.d!=y.d)return x.d<y.d;
else return x.id<y.id;
}
map<int,int> mm;
int main()
{
freopen("hdu3726.in","w",stdout);
srand(time(NULL));int T;
T=10;
while(T--){
int n=rand()%10+5,m=n;mm.clear();
printf("%d %d\n",n,m);
for (int i=1;i<=n;++i) printf("%d\n",rand());
for(int i=1;i<=n;i++)
{
d[i].d=1;
d[i].id=i;
}
for(int i=1;i<=n-2;i++)a[i]=rand()%n+1;//生成purfer编码
for(int i=1;i<=n-2;i++)d[a[i]].d++;//累加度数
for(int i=1;i<=n-2;i++)
{
sort(d+1,d+n+1,cmp);
int j,f=1;int rd=rand();if (rd&1) f=-1;
for(j=1;j<=n;j++)if(d[j].d)break;
printf("%d %d\n",d[j].id,a[i]);
d[j].d--;
sort(d+1,d+n+1,cmpid);
d[a[i]].d--;
} //模拟上述过程,找度数为1且编号最小的和purfer编码中当前位
sort(d+1,d+n+1,cmp);
printf("%d %d\n",d[n-1].id,d[n].id);//最后两个点之间连边
/*for(int i=1;i<=n;i++)
{
printf("%d ",(rand()%20)-10);
}*/
//int m=rand()%20+1;
/*for (int i=2;i<=n;++i){
printf("%d %d\n",rand()%(i-1)+1,i);
}*/
for (int i=1;i<=m-(n-1);++i) printf("%d %d\n",rand()%n+1,rand()%n+1);
cout<<endl;int cnt=0;
while(cnt++<=10)
{
int s=rand()%3+1;
if(s==1){
bool flag=1;int cnt=0;bool ff=1;
while(flag){
int x=rand()%m+1;if (!mm[x]) printf("D %d\n",x),mm[x]=1,flag=0;++cnt;
if(cnt>1000) {ff=0;break;}
}
if (!ff) continue;
}
if(s==2){
int rd=rand(),f=1;if (rd&1) f=-1;
printf("Q ");int x=rand()%n+1,k=f*rand()%n+1;printf("%d %d\n",x,k);
}
if(s==3){
printf("C ");int x=rand()%n+1,yy=rand()*((rand()&1)?1:-1);
printf("%d %d\n",x,yy);
}
/*int a=rand()%n+1;
int b=rand()%a+1;
while(a==b)
{
a=rand()%n+1;
b=rand()%a+1;
}
cout<<a<<" "<<b<<endl;*/
}puts("E");
}puts("0 0");
return 0;
}