Cod sursa(job #1491257)

Utilizator daniel.grosuDaniel Grosu daniel.grosu Data 24 septembrie 2015 23:46:56
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 9.88 kb
#define REP(a,b) for(int a=0; a<(b); ++a)
#define REP2(a,b) for(int a=1; a<=(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b)-1; a>=(c); --a)
#define BCK2(a,b,c) for(int a=(b); a>(c); --a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define ALL(a) (a).begin(), (a).end()
#define SIZE(a) ((int)(a).size())
#define VAR(x) #x ": " << x << " "
#define FILL(x,y) memset(x,y,sizeof(x))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define FAST ios_base::sync_with_stdio(0);cin.tie(0);
#define x first
#define y second
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define l(n) (n<<1)
#define r(n) ((n<<1)+1)
#define f(n) (n>>1)
#define lsb(a) (a&-a)

#include<vector>
#include<stack>
#include<queue>
#include<algorithm>

using namespace std;
#ifndef ONLINE_JUDGE
#include<fstream>
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
#else
#include<iostream>
#endif

const int NMAX = 100015;
const int dx[] = {0, 0, -1, 1}; //1,1,-1,1};
const int dy[] = {-1, 1, 0, 0}; //1,-1,1,-1};

typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;

int N,M,A[NMAX]; 

VI G[NMAX], P[NMAX]; // Graph and paths
int path[NMAX]; // Index of the path on which node n stands;
int conn[NMAX]; // The connection node of the path to the above path
int conn_lvl[NMAX]; // The connection node lvl; a.k.a. the starting high level;
int length[NMAX]; // The length of the path
int position[NMAX]; // The starting position of the path in the ST.
int K;

int segment[4*NMAX];

bool viz[NMAX]; // use for DFS
int w[NMAX]; // weight
int lvl[NMAX]; // depth of the node starting from the root

int asd=0;

void dfs(int n)
{
    //cout<<"n = "<<n<<" ";
    
    viz[n]=true;
    w[n]=1;
    
    int son=0;
    bool end=true;
    REP(i,G[n].size())
    {
        int curr=G[n][i];
        if(!viz[curr])
        {
            end=false;
            lvl[curr]=lvl[n]+1;
            dfs(curr);
            
            w[n]+=w[curr];
            if(!son)
                son=curr;
            else
                if(w[son] < w[curr])
                    son=curr;
        }
    }
    if(end) // it's a leaf so we create a new path
    {
        //cout<<"new path \n";
        path[n]=++K;
        length[path[n]]=1;
        P[path[n]].pb(n);
        return;
    }
    // it's not a leaf so adhere this node to the path of the chosen son
    
    path[n]=path[son];
    ++length[path[n]];
    P[path[son]].pb(n);

    // connect the paths ending in this node to this node
    REP(i, G[n].size())
    {
        int curr=G[n][i];
        if(curr == son || lvl[curr] < lvl[n])
            continue;

        conn[path[curr]]=n;
        //cout<<"conn["<<path[curr]<<"] = "<<n<<" \n";
        conn_lvl[path[curr]]=lvl[n];

    }
    
}

void build(int n, int l, int r, int phi, int path)
{
    if(l==r)
    {
        segment[n + phi] = A[P[path][l-1]];
        return;
    }
    
    int pivot = (l + r)/2;
    
    build(l(n), l, pivot, phi, path);
    build(r(n), pivot+1, r, phi, path);
    
    segment[n + phi] = MAX(segment[l(n) + phi], segment[r(n) + phi]);
}

void update(int n, int l, int r, int poz, int val, int phi)
{
    if(l==r)
    {
        segment[n + phi]=val;
        //cout<<"updated ! "<<"\n";
        return;
    }
    
    int pivot = (l+r)>>1;
    
    if(poz <= pivot)
        update(l(n), l, pivot, poz, val, phi);
    else
        update(r(n), pivot+1, r, poz, val, phi);
    
    segment[n + phi] = MAX(segment[l(n) + phi], segment[r(n) + phi]);
    //cout<<" go back "<<"\n";
}


int query(int n, int l, int r, int x, int y, int phi)
{
    if(x <= l && r <= y)
        return segment[n + phi];
 
    int med = (l + r) / 2, rez = 0;
 
    if(x <= med)
        rez = max(rez, query(n * 2, l, med, x, y, phi));
    if(med < y)
        rez = max(rez, query(n * 2 + 1, med + 1, r, x, y, phi));
 
    return rez;
}


int main(){
    FAST;
    cin>>N>>M;
    REP2(i,N)
        cin>>A[i];
    REP(i,N-1)
    {
        int x,y;
        cin>>x>>y;
        //cout<<x<<" "<<y<<" \n";
        G[x].pb(y); G[y].pb(x);
    }
    //cout<<"end \n";
    // DFS AND BUILD PATHS
        lvl[1]=1;
        dfs(1); // build the paths;
        //cout<<"k = "<<K<<"\n";
        cout<<"K IS "<<K<<" \n";
        REP2(i, K)
        {
            reverse(P[i].begin(), P[i].end()); // reverse the paths so its starting with the lowest level node.
            if(i>1)
                position[i] = position[i-1] + 4*length[i-1]; // why is 4 is intelligible to me....
            build(1, 1, length[i], position[i], i);
            //cout<<"new \n";
        }
    // ----
        int t,x,y,sol=0;
    REP(i,M)
    {
        cin>>t>>x>>y;
        
        //cout<<" doo for "<<t<<" "<<x<<" "<<y<<" \n"; 
        if(t==0)
        {
            update(1, 1, length[path[x]], lvl[x] - conn_lvl[path[x]], y, position[path[x]]);
        }
        else
        {
            sol=0;
            while(1)
            {
                asd++;
                if(path[x] == path[y])
                {
                    //cout<<"path["<<x<<"] = path["<<y<<"]"<<"\n";
                    if(lvl[x] > lvl[y])
                        swap(x,y);
                    sol = MAX(sol, query(1, 1, length[path[x]], lvl[x]-conn_lvl[path[x]], lvl[y]-conn_lvl[path[x]], position[path[x]]));
                    break;
                }
                if(conn_lvl[path[x]] < conn_lvl[path[y]])
                    swap(x,y);
                
                sol = MAX(sol, query(1, 1, length[path[x]], 1, lvl[x] - conn_lvl[path[x]], position[path[x]]));
                
                //cout<<conn[path[x]]<<" ";
                x=conn[path[x]];
            }
            //cout<<"sol = ";
            cout<<sol<<" "<<asd<<" "<<"\n";
        
        }
    }
    cout<<" K is "<<K<<" ";
    return 0;
}

/*
//Heavy Path Decomposition, O(N * log N * log N)
 
#include <cstdio>
#include <algorithm>
#include <vector>
#include <utility>
 
using namespace std;
 
#define MAXN 100010
 
int N, M, nL;
int v[MAXN], fol[MAXN], niv[MAXN], w[MAXN], l[MAXN];
int aint[4*MAXN];
int lTata[MAXN], lNiv[MAXN], lDim[MAXN], lPoz[MAXN];
vector<int> G[MAXN], P[MAXN];
pair<int, pair<int, int> > op[MAXN];
int asd=0;
void citire()
{
    scanf("%d%d", &N, &M);
    for(int i = 1; i <= N; ++i)
        scanf("%d", &v[i]);
 
    int a, b;
    for(int i = 1; i < N; ++i)
    {
        scanf("%d%d", &a, &b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
 
    int t, x, y;
    for(int i = 1; i <= M; ++i)
    {
        scanf("%d%d%d", &t, &x, &y);
        op[i] = make_pair(t, make_pair(x, y));
    }
}
 
void df(int nod)
{
    fol[nod] = 1;
    w[nod] = 1;
 
    int hN = -1, frunza = 1;
 
    for(vector<int> :: iterator it = G[nod].begin(); it != G[nod].end(); ++it)
    {
        if(fol[*it])
            continue;
 
        frunza = 0;
        niv[*it] = niv[nod] + 1;
 
        df(*it);
 
        w[nod] += w[*it];
 
        if(hN == -1)
            hN = *it;
        else
        if(w[hN] < w[*it])
            hN = *it;
    }
 
    if(frunza)
    {
        l[nod] = ++nL;
        lDim[nL]=1;
        P[nL].push_back(nod);
        return;
    }
 
    l[nod] = l[hN];
    ++lDim[l[nod]];
    P[l[nod]].push_back(nod);
 
    for(vector<int> :: iterator it = G[nod].begin(); it != G[nod].end(); ++it)
    {
        if((*it) == hN || niv[*it] < niv[nod])
            continue;
 
        lTata[l[*it]] = nod;
        lNiv[l[*it]] = niv[nod];
    }
}
 
void build(int nod, int left, int right, int decalaj, int lant)
{
    if(left == right)
    {
        aint[nod + decalaj] = v[ P[lant][left - 1] ];
        return;
    }
 
    int med = (left + right) / 2;
 
    build(nod * 2, left, med, decalaj, lant);
    build(nod * 2 + 1, med+1, right, decalaj, lant);
 
    aint[nod + decalaj] = max(aint[nod * 2 + decalaj], aint[nod * 2 + 1 + decalaj]);
}
 
void make_paths()
{
    niv[1] = 1;
    df(1);
 
    for(int i = 1; i <= nL; ++i)
    {
        reverse(P[i].begin(), P[i].end());
 
        if(i > 1)
            lPoz[i] = lPoz[i-1] + lDim[i-1] * 4;
 
        build(1, 1, lDim[i], lPoz[i], i);
    }
}
 
void update(int nod, int left, int right, int poz, int val, int decalaj)
{
    if(left == right)
    {
        aint[nod + decalaj] = val;
        return;
    }
 
    int med = (left + right) / 2;
 
    if(poz<=med)
        update(nod * 2, left, med, poz, val, decalaj);
    else
        update(nod * 2 + 1, med+1, right, poz, val, decalaj);
 
    aint[nod + decalaj] = max(aint[nod * 2 + decalaj], aint[nod * 2 + 1 + decalaj]);
}
 
int query(int nod, int left, int right, int qleft, int qright, int decalaj)
{
    asd++;
    if(qleft <= left && right <= qright)
        return aint[nod + decalaj];
 
    int med = (left + right) / 2, rez = 0;
 
    if(qleft <= med)
        rez = max(rez, query(nod * 2, left, med, qleft, qright, decalaj) );
    if(med < qright)
        rez = max(rez, query(nod * 2 + 1, med + 1, right, qleft, qright, decalaj) );
 
    return rez;
}
 
void solve()
{
    int t, x, y, sol = 0;
 
    for(int i = 1; i <= M; ++i)
    {
        t = op[i].first; x = op[i].second.first, y = op[i].second.second;
        if(t==0)
            update(1, 1, lDim[l[x]], niv[x] - lNiv[l[x]], y, lPoz[l[x]]);
        else
        {
            sol = 0;
            while(1)
            {
                asd++;
                if(l[x] == l[y])
                {
                    if(niv[x] > niv[y])
                        swap(x, y);
                    sol = max(sol, query(1, 1, lDim[l[x]], niv[x] - lNiv[l[x]], niv[y] - lNiv[l[x]], lPoz[l[x]]) );
                    break;
                }
 
                if(lNiv[l[x]] < lNiv[l[y]])
                    swap(x, y);
 
                sol = max(sol, query(1, 1, lDim[l[x]], 1, niv[x] - lNiv[l[x]], lPoz[l[x]]) );
 
                x = lTata[l[x]];
            }
            printf("%d %d\n", sol, asd);
        }
    }
}
 
int main()
{
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);
 
    citire();
    make_paths();
    solve();
 
    return 0;
}
*/