zoukankan      html  css  js  c++  java
  • LA 5031

     Graph and Queries

    Time limit: 3.000 second

    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$ le$N$ le$* 104, 0$ le$M$ le$* 104), the number of vertexes in the graph. The next N lines describes the initial weight of each vertex (- 106$ le$[weight][i]$ le$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 * 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.


    Explanation for samples:

    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

    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

    有关数据结构有Treap树,并查集,同时离线算法的设计。

    /*
    * @author  Panoss
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<list>
    using namespace std;
    #define DBG 0
    #define fori(i,a,b) for(int i = (a); i < (b); i++)
    #define forie(i,a,b) for(int i = (a); i <= (b); i++)
    #define ford(i,a,b) for(int i = (a); i > (b); i--)
    #define forde(i,a,b) for(int i = (a); i >= (b); i--)
    #define forls(i,a,b,n) for(int i = (a); i != (b); i = n[i])
    #define mset(a,v) memset(a, v, sizeof(a))
    #define mcpy(a,b) memcpy(a, b, sizeof(a))
    #define dout  DBG && cerr << __LINE__ << " >>| "
    #define checkv(x) dout << #x"=" << (x) << " | "<<endl
    #define checka(array,a,b) if(DBG) { 
        dout << #array"[] | " << endl; 
        forie(i, a, b) cerr << "[" << i << "]=" << array[i] << " |" << ((i - (a)+1) % 5 ? " " : "
    "); 
    if (((b)-(a)+1) % 5) cerr << endl; 
    }
    #define redata(T, x) T x; cin >> x
    #define MIN_LD -2147483648
    #define MAX_LD  2147483647
    #define MIN_LLD -9223372036854775808
    #define MAX_LLD  9223372036854775807
    #define MAX_INF 18446744073709551615
    inline int  reint() { int d; scanf("%d", &d); return d; }
    inline long relong() { long l; scanf("%ld", &l); return l; }
    inline char rechar() { scanf(" "); return getchar(); }
    inline double redouble() { double d; scanf("%lf", &d); return d; }
    inline string restring() { string s; cin >> s; return s; }
    
    struct Treap_node
    {
        int value, priority, s;         ///键值,优先级,总结点数(从根(包括根)开始往下算的结点个数)
        struct Treap_node * child[2];
        Treap_node(int v): value(v)
        {
            child[0] =  child[1] = NULL;
            priority = rand();
            s = 1;
        }
        bool operator < (const Treap_node & X) const
        {
            return priority < X.priority;
        }
        int compare(int v)
        {
            if(v == value) return -1;
            return v < value ? 0 : 1;
        }
        void updata()
        {
            s = 1;
            if(child[0]) s += child[0]->s;
            if(child[1]) s += child[1]->s;
        }
    };
    
    void Rotate(Treap_node* &root, int d)  ///0左旋(逆时针),1右旋(顺时针)
    {
        Treap_node * k = root->child[d^1];
        root->child[d^1] = k->child[d];
        k->child[d] = root;
        root->updata();
        k->updata();
        root = k;
    }
    
    void Insert_node(Treap_node* &root, int v)
    {
        if(!root)
        {
            root = new Treap_node(v);
        }
        else
        {
            int d = (v < root->value ? 0 : 1);     ///若允许有相同结点
            ///int d = root->compare(v);           ///若不允许有相同结点
            Insert_node(root->child[d], v);
            if(root->child[d] > root) Rotate(root, d^1);
        }
        root->updata();
    }
    
    void Remove_node(Treap_node * &root, int v)
    {
        int d = root->compare(v);
    
        if(d == -1)
        {
            Treap_node * temp = root;
    
            if(root->child[0] && root->child[1])
            {
                int dir = root->child[0] > root->child[1] ? 1:0;
                Rotate(root, dir);
                Remove_node(root->child[dir], v);
            }
            else
            {
                if(!root->child[0]) root = root->child[1];
                else root = root->child[0];
    
                delete temp;
            }
        }
        else
        {
            Remove_node(root->child[d], v);
        }
    
        if(root) root->updata();
    }
    
    bool Find_node(Treap_node * root, int v)
    {
        while(root)
        {
            int d = root->compare(v);
            if(d ==  -1) return true;
            else root = root->child[d];
        }
        return false;
    }
    
    const int MAXN = 20000 + 10;
    const int MAXM = 60000 + 10;
    const int MAXC = 400000 + 10;
    
    struct Command
    {
        char op;
        int x, p; ///p = k or v
    };
    
    Command cmd[MAXC];
    
    int f[MAXN];
    int Find(int x) {return f[x] == x? x : f[x] = Find(f[x]);}
    
    int from[MAXM], to[MAXM], weight[MAXN];
    bool removed[MAXM];
    
    Treap_node * Tree[MAXN];
    
    int K_th(Treap_node * root, int k)
    {
        if(!root || k <= 0 || k > root->s) return 0;
        int s = (root->child[1]==NULL?0:root->child[1]->s);
        if(k == s+1) return root->value;
        else if(k <= s) return K_th(root->child[1],k);
        else return  K_th(root->child[0],k-s-1);
    }
    
    void Merge_Tree(Treap_node* &from_root, Treap_node * &to_root)
    {
        if(from_root->child[0]) Merge_Tree(from_root->child[0],to_root);
        if(from_root->child[1]) Merge_Tree(from_root->child[1],to_root);
        Insert_node(to_root,from_root->value);
        delete from_root;
        from_root = NULL;
    }
    
    void Remove_Tree(Treap_node * &root)
    {
        if(root->child[0]) Remove_Tree(root->child[0]);
        if(root->child[1]) Remove_Tree(root->child[1]);
        delete root;
        root = NULL;
    }
    
    void Add_Edge(int e)
    {
        int u = Find(from[e]), v = Find(to[e]);
        if(u!=v)
        {
            if(Tree[u]->s < Tree[v]->s)
            {
                f[u] = v;
                Merge_Tree(Tree[u],Tree[v]);
            }
            else
            {
                f[v] = u;
                Merge_Tree(Tree[v],Tree[u]);
            }
        }
    }
    
    int query_cnt;
    long long query_tot;
    
    void Query(int x, int k)
    {
        query_cnt ++;
        query_tot += K_th(Tree[Find(x)], k);
    }
    
    void Change_weight(int x, int v)
    {
        int u = Find(x);
        Remove_node(Tree[u], weight[x]);
        Insert_node(Tree[u], v);
        weight[x] = v;///
    }
    
    int main()
    {
        int Case = 0;
        int n,m;
        while(scanf("%d%d",&n,&m)==2&&(n+m))
        {
            Case ++;
    
            forie(i,1,n) scanf("%d",&weight[i]);
            forie(i,1,m) scanf("%d%d",&from[i],&to[i]);
    
            ///Init
            mset(removed,false);
            forie(i,1,n) f[i] = i;
            query_cnt = query_tot = 0;
    
            int c = 0;
            for(;;)
            {
                char op;
                int x , p = 0, v = 0;
                scanf(" %c",&op);
                if(op == 'E') break;
                scanf("%d",&x);
                if(op == 'D') removed[x] = true;
                if(op == 'Q') scanf("%d",&p);
                if(op == 'C')
                {
                    scanf("%d",&v);
                    p = weight[x];
                    weight[x] = v;
                }
                cmd[++c] = (Command){op,x,p};
            }
    
            forie(i,1,n)
            {
                if(Tree[i]) Remove_Tree(Tree[i]);
                Tree[i] = new Treap_node(weight[i]);
            }
    
            forie(i,1,m)
                if(!removed[i]) Add_Edge(i);
    
            forde(i,c,1)
            {
                if(cmd[i].op == 'D') Add_Edge(cmd[i].x);
                if(cmd[i].op == 'Q') Query(cmd[i].x,cmd[i].p);
                if(cmd[i].op == 'C') Change_weight(cmd[i].x,cmd[i].p);
            }
            printf("Case %d: %.6lf
    ",Case,query_tot/(double)query_cnt);
        }
        return 0;
    }
  • 相关阅读:
    USACO 3.3 A Game
    USACO 3.3 Camelot
    USACO 3.3 Shopping Offers
    USACO 3.3 TEXT Eulerian Tour中的Cows on Parade一点理解
    USACO 3.3 Riding the Fences
    USACO 3.2 Magic Squares
    USACO 3.2 Stringsobits
    USACO 3.2 Factorials
    USACO 3.2 Contact
    USACO 3.1 Humble Numbers
  • 原文地址:https://www.cnblogs.com/Panoss/p/3810243.html
Copyright © 2011-2022 走看看