hdu3726 Graph and Queries

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值