hdu 5002 Tree

Tree

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 366    Accepted Submission(s): 163

Problem Description

You are given a tree with N nodes which are numbered by integers 1..N. Each node is associated with an integer as the weight.

Your task is to deal with M operations of 4 types:

1.Delete an edge (x, y) from the tree, and then add a new edge (a, b). We ensure that it still constitutes a tree after adding the new edge.

2.Given two nodes a and b in the tree, change the weights of all the nodes on the path connecting node a and b (including node a and b) to a particular value x.

3.Given two nodes a and b in the tree, increase the weights of all the nodes on the path connecting node a and b (including node a and b) by a particular value d.

4.Given two nodes a and b in the tree, compute the second largest weight on the path connecting node a and b (including node a and b), and the number of times this weight occurs on the path. Note that here we need the strict second largest weight. For instance, the strict second largest weight of {3, 5, 2, 5, 3} is 3.

Input

The first line contains an integer T (T<=3), which means there are T test cases in the input.

For each test case, the first line contains two integers N and M (N, M<=10^5). The second line contains N integers, and the i-th integer is the weight of the i-th node in the tree (their absolute values are not larger than 10^4).

In next N-1 lines, there are two integers a and b (1<=a, b<=N), which means there exists an edge connecting node a and b.

The next M lines describe the operations you have to deal with. In each line the first integer is c (1<=c<=4), which indicates the type of operation.

If c = 1, there are four integers x, y, a, b (1<= x, y, a, b <=N) after c.
If c = 2, there are three integers a, b, x (1<= a, b<=N, |x|<=10^4) after c.
If c = 3, there are three integers a, b, d (1<= a, b<=N, |d|<=10^4) after c.
If c = 4 (it is a query operation), there are two integers a, b (1<= a, b<=N) after c.

All these parameters have the same meaning as described in problem description.

Output

For each test case, first output "Case #x:"" (x means case ID) in a separate line.

For each query operation, output two values: the second largest weight and the number of times it occurs. If the weights of nodes on that path are all the same, just output "ALL SAME" (without quotes).

Sample Input

2
3 2
1 1 2
1 2
1 3
4 1 2
4 2 3
7 7
5 3 2 1 7 3 6
1 2
1 3
3 4
3 5
4 6
4 7
4 2 6
3 4 5 -1
4 5 7
1 3 4 2 4
4 3 6
2 3 6 5
4 3 6

Sample Output

Case #1:
ALL SAME
1 2
Case #2:
3 2
1 1
3 2
ALL SAME

Source

2014 ACM/ICPC Asia Regional Anshan Online

思路:lct,就是有点繁琐。。==

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define INF 89898989
#define mod 20140518
#define maxn 100010
using namespace std;

int head[maxn],next1[maxn*2],to[maxn*2] ;
int top ,n ;
bool vi[maxn] ;

void Unit(int u,int v )
{
    next1[top] = head[u] ;to[top] = v ;
    head[u] = top++;
}
struct LCT
{
    int w[maxn],add[maxn],Max1[maxn];
    int ch[maxn][2],pre[maxn] ;
    int set1[maxn],Max2[maxn];
    int num1[maxn],num2[maxn];
    int size1[maxn];
    int rev[maxn] ;
    void init()
    {
        memset(rev,0,sizeof(rev)) ;
        memset(ch,0,sizeof(ch)) ;
        memset(add,0,sizeof(add));
        memset(pre,0,sizeof(pre)) ;
        memset(size1,0,sizeof(size1));
        memset(num2,1,sizeof(num2));
    }
    void update(int x )
    {
        size1[x] = size1[ch[x][1]]+1+size1[ch[x][0]];
        Max1[x] = w[x] ;
        num1[x]=1;
        num2[x]=1;
        Max2[x] = -INF;
        int ls=ch[x][0],rs=ch[x][1];
        hehe(Max1[x],num1[x],Max2[x],num2[x],ls) ;
        hehe(Max1[x],num1[x],Max2[x],num2[x],rs) ;
    }
    void Add(int x ,int val)
    {
        if(x)
        {
            add[x] += val ;
            w[x] += val ;
            Max1[x] += val ;
            if(Max2[x] != -INF)Max2[x] += val ;
        }
    }
    void Set(int x,int val)
    {
        if(x)
        {
            add[x] = 0 ;
            Max1[x] = val ;
            num1[x] = size1[x];
            Max2[x] = -INF ;
            num2[x] = 1;
            set1[x] = val;
            w[x] = val ;
        }
    }
    void down(int x )
    {
        if(set1[x] != INF)
        {
            Set(ch[x][0],set1[x]) ;
            Set(ch[x][1],set1[x]) ;
            set1[x] = INF;
        }
        if(add[x])
        {
            Add(ch[x][0],add[x]) ;
            Add(ch[x][1],add[x]) ;
            add[x]=0;
        }
        if(rev[x])
        {
            swap(ch[x][0],ch[x][1]) ;
            rev[ch[x][0]] ^= 1;
            rev[ch[x][1]] ^= 1;
            rev[x] = 0;
        }
    }
    bool isroot(int x )
    {
        if(ch[pre[x]][0] != x && ch[pre[x]][1] != x )
            return true ;
        return false;
    }
    void pushdown(int x )
    {
        if(!isroot(x)) pushdown(pre[x]) ;
        down(x) ;
    }
    void rotate(int x,int f)
    {
        int y = pre[x],z = pre[y];
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(ch[z][0] == y)ch[z][0] = x;
        else if(ch[z][1] == y)ch[z][1] = x;
        pre[y] = x;
        ch[x][f] = y;
        update(y);
    }
    void splay(int x)
    {
        pushdown(x);
        while(!isroot(x))
        {
            if(isroot(pre[x]))rotate(x,ch[pre[x]][0] == x);
            else
            {
                int y = pre[x],z = pre[y];
                int f = (ch[z][0] == y);
                if(ch[y][f] == x)rotate(x,!f),rotate(x,f);
                else rotate(y,f),rotate(x,f);
            }
        }
        update(x);
    }
    void access(int u)
    {
        for(int f = 0 ; u ;u = pre[u])
        {
            splay(u);
            ch[u][1] = f ;
            update(u);
            f = u ;
        }
    }
    bool check(int a ,int b)
    {
        int x =a,y=b;
        access(y) ;
        for(int f = 0 ;x ;x = pre[x])
        {
            splay(x) ;
            if(!pre[x]) break ;
            f = x ;
        }
        for( ; ch[x][1] ; x = ch[x][1]);
        return x == b ;
    }
    void make_root(int x )
    {
        access(x) ;
        splay(x) ;
        rev[x] ^= 1;
    }
    void cut(int x,int y )
    {
        make_root(x) ;
        splay(y) ;
        pre[ch[y][0]] = pre[y] ;
        pre[y] = ch[y][0] = 0 ;
    }
    void hehe(int &m1,int &n1,int &m2,int &n2,int x )
    {
        if(!x) return ;
        if(Max1[x]==m1)
        {
            n1 += num1[x] ;
            if(Max2[x] > m2)
            {
                m2 = Max2[x] ;
                n2 = num2[x] ;
            }
            else if(Max2[x]==m2)
            {
                n2 += num2[x] ;
            }
        }
        else if(Max1[x] > m1)
        {
            if(m1 == Max2[x])
            {
                m2 = m1;
                n2 = n1+num2[x] ;
            }
            else if(m1 > Max2[x])
            {
                m2 = m1;
                n2 = n1;
            }
            else
            {
                m2 = Max2[x] ;
                n2 = num2[x] ;
            }
            n1 = num1[x] ;
            m1 = Max1[x] ;
        }
        else
        {
            if(m2==Max1[x])
            {
                n2 += num1[x] ;
            }
            else if(Max1[x] > m2)
            {
                m2 = Max1[x] ;
                n2 = num1[x] ;
            }
        }
    }
    int find(int x,int y,int &num)
    {
        access(y) ;
        for( int f = 0 ; x ; x = pre[x])
        {
            splay(x) ;
            if(!pre[x])
            {
                int n1=1,m1=w[x],m2=-INF,n2=0;
                hehe(m1,n1,m2,n2,f) ;
                hehe(m1,n1,m2,n2,ch[x][1]) ;
                num = n2 ;
                return m2;
            }
            ch[x][1] = f ;
            f = x ;
            update(x) ;
        }
        return -1;
    }
    void add1(int x ,int y ,int add)
    {
        access(y) ;
        for(int f = 0 ; x ; x = pre[x])
        {
            splay(x) ;
            if(!pre[x])
            {
                w[x] += add ;
                Max1[x] += add ;
                if(Max2[x] != -INF) Max2[x] += add;
                Add(f,add) ;
                Add(ch[x][1],add) ;
                return ;
            }
            ch[x][1] = f ;
            f = x ;
            update(x) ;
        }
    }
    void SET(int x ,int y ,int s)
    {
        access(y) ;
        for(int f = 0 ; x ; x = pre[x])
        {
            splay(x) ;
            if(!pre[x])
            {
                w[x] = s;
                set1[x] = INF;
                Max1[x] = s;
                num1[x] = size1[x] ;
                num2[x] = 1;
                Max2[x] = -INF;
                Set(f,s) ;
                Set(ch[x][1],s) ;
                return ;
            }
            ch[x][1] = f ;
            f = x ;
            update(x) ;
        }
    }
    void link(int x,int y )
    {
        make_root(x) ;
        splay(x);
        pre[x]=y;
    }
}lct;
void dfs(int u,int f)
{
    for(int i = head[u]; i != -1; i=next1[i])
    {
        int v = to[i] ;
        if(v==f) continue ;
        dfs(v,u);
        lct.pre[v] = u;
    }
}
int next_int() {
    char ch;
    int res;
    bool neg;
    while (ch = getchar(), !isdigit(ch) && ch != ‘-‘)
        ;
    if (ch == ‘-‘) {
        neg = true;
        res = 0;
    } else {
        neg = false;
        res = ch - ‘0‘;
    }
    while (ch = getchar(), isdigit(ch))
        res = res * 10 + ch - ‘0‘;
    return neg ? -res : res;
}
int main()
{
    int n,m,i,j,k,num;
    int T,case1=0,u,v,c ;
   // freopen("in.txt","r",stdin);
    cin >> T ;
    while(T--)
    {
        scanf("%d%d",&n,&m) ;
        lct.init();
        for( i = 1 ; i <= n ;i++)
        {
            lct.w[i] = next_int() ;
            lct.set1[i]=INF;
            lct.Max2[i]=-INF;
        }
        top=0;
        memset(head,-1,sizeof(head)) ;
        for( i = 1 ; i < n ;i++)
        {
            u = next_int();
            v = next_int();
            Unit(u,v) ;
            Unit(v,u) ;
        }
        dfs(1,-1);
        printf("Case #%d:\n",++case1);
        while(m--)
        {
            //scanf("%d%d%d",&u,&v,&c) ;
            scanf("%d",&k) ;
            if(k==1)
            {
              //  scanf("%d%d",&u,&v) ;
                u = next_int();
                v = next_int();
                lct.cut(u,v) ;
               // scanf("%d%d",&u,&v) ;
                u = next_int();
                v = next_int();
                lct.link(u,v) ;
            }
            else if(k==2)
            {
             //   scanf("%d%d%d",&u,&v,&c) ;
                u = next_int();
                v = next_int();
                c = next_int();
                lct.SET(u,v,c) ;
            }
            else if(k==3)
            {
                scanf("%d%d%d",&u,&v,&c) ;
                lct.add1(u,v,c) ;
            }
            else{
               // scanf("%d%d",&u,&v) ;
                u = next_int();
                v = next_int();
                j = lct.find(u,v,num) ;
                if(j==-INF) puts("ALL SAME");
                else printf("%d %d\n",j,num);
            }
        }
    }
    return 0 ;
}

  

时间: 2024-08-02 21:03:24

hdu 5002 Tree的相关文章

HDU 5002 Tree (2014年鞍山赛区网络赛F题)

1.题目描述:点击打开链接 2.解题思路:LCT的模板题 3.代码: #include <cstdio> #include <cstdlib> #include <algorithm> #include <iostream> #include <vector> using namespace std; const int N = 111111; const int INF = 1111111111; int n, m; class LCT { p

HDU 5002 Tree(动态树LCT)(2014 ACM/ICPC Asia Regional Anshan Online)

Problem Description You are given a tree with N nodes which are numbered by integers 1..N. Each node is associated with an integer as the weight. Your task is to deal with M operations of 4 types: 1.Delete an edge (x, y) from the tree, and then add a

hdu 5002 (动态树lct)

Tree Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 920    Accepted Submission(s): 388 Problem Description You are given a tree with N nodes which are numbered by integers 1..N. Each node is a

hdu 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")

hdu 5370 Tree Maker(catalan+dp)

题目链接:hdu 5370 Tree Maker n个节点的二叉树种类为Catalan数的第n项 对于一棵子树而言,被移动过的节点就是确定的位置,所以只要知道已经确定位置的K个节点有多少个空孩子指针M,和就该子树下的N个未确定位置的节点,等于是说用N个节点构造M个可为空的子树的种类数.对于整个树的形态数即为若干棵独立的子树形态数的乘积. 定义dp[i][j]为用i个节点构造j棵树的形态数,dp[i][j] = sum{ dp[i-1][j-k] * catalan[k] | 0 ≤ k ≤j }

HDU 5044 Tree(树链剖分)

HDU 5044 Tree 题目链接 就简单的树链剖分,不过坑要加输入外挂,还要手动扩栈 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 100005; #pragma comment(linker, "/STACK:1024000000,1024000000"

hdu 4757 Tree(可持久化字典树)

题目链接:hdu 4757 Tree 题目大意:给定一棵树,每一个节点有一个值.如今有Q次询问,每次询问u到v路径上节点值与w亦或值的最大值. 解题思路:刚開始以为是树链剖分,事实上树链剖分仅仅是用来求LCA(能够不用树链剖分). 可持久化字典树.在每次插入的同一时候,不改动原先的节点.而是对全部改动的节点复制一个新的节点,而且在新的节点 上做操作,这样做的目的是可以获取某次改动前的状态.同过可持久化的操作,保留了改动前后的公共数据. 对给定树上的全部节点权值建立01字典树,然后每一个节点都保存

hdu 3534 Tree(树形DP)

题目链接:hdu 3534 Tree 题意: 给你一棵n个节点,n-1条边的树,每条边有一个长度,现在问你最长的边的长度为多少,有多少条. 题解: 其实这种题不用记录最长和次长,我们开两个数组,len[i],num[i]. 表示以i为根结点出发的最长的长度以及最长的边的条数. 然后我们只需要一个dfs,先用子节点的信息来更新答案,然后在更新当前节点的len和num记录的信息. 这样就不用记录最长和次长. 1 #include<bits/stdc++.h> 2 #define mst(a,b)

HDU 1710-Binary Tree Traversals(重建二叉树)

Binary Tree Traversals Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3340    Accepted Submission(s): 1500 Problem Description A binary tree is a finite set of vertices that is either empty or