LINK 913 Query on a tree II

spoj face questions

Time limit 433 ms // time spoj are so strange

Memory limit 1572864 kB //1.5 a G, crazy

Code length Limit 15000 B

Linux OS

Language limit All except: ERL JS-RHINO NODEJS PERL6 VB.NET

Source Special thanks to Ivan Krasilnikov for his alternative solution

Author Thanh-Vy Hua

Make complaints

A second mid-term energy problems, the results to write for half an hour, hour and a half ...... tune in memory of the second channel is killed by multiple sets ...... Case read this question is the subject of a case before the next two readings came in, that time is of the case did not finish into the next case, and this over the next two weeks ah ...... this sample measured in relation to a sample copy more than a few times ......

By the way Tucao, this is valid data ah ...... one step up violence can jump A, I jump heavy loss ...... case and add a blank line between this requirement it will not be sentenced, without adding blank lines are AC

Problem-solving ideas

I saw this question not think a direct chain split on the tree, the results of finished react overkill, this problem dfs pre-again, doubling the tree and jump statistical results are better ways to short code can not less.

Tree split processing chain \ (KTH \) operation is the use of a Type: id node on a new heavy chain, is continuous from top to bottom, so that if it is found when the chain skips jump target \ (K \) , then both ends of the direct use of this new heavy chain \ (ID \) calculates the target \ (K \) a \ (ID \) , and then converted to the original number.

Source

#include<stdio.h>
#include<string.h>
#include<algorithm>
int T;
int n;

struct Edge{
    int nxt,to,w;
}e[200010];
int head[100010],cnt;
void add(int u,int v,int w)
{
    e[cnt]={head[u],v,w};
    head[u]=cnt++;
    e[cnt]={head[v],u,w};
    head[v]=cnt++;
}

struct Tree{
    int fa,dep,w,sz,wson;
    int top,id;
}t[100010];
void dfs1(int fa,int u,int w)
{
    t[u].fa=fa;
    t[u].dep=t[fa].dep+1;
    t[u].w=w;
    t[u].sz=1;
    int maxn=0;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa) continue;
        dfs1(u,v,e[i].w);
        int temp=t[v].sz;
        t[u].sz+=temp;
        if(temp>maxn)
        {
            maxn=temp;
            t[u].wson=v;
        }
    }
}
int id=1;
int mp[100010];//用新id查询老id
long long a[100010];
void dfs2(int u,int top)
{
    t[u].top=top;
    t[u].id=id;
    a[id]=t[u].w;
    mp[id]=u;
    id++;
    if(t[u].sz==1) return;
    dfs2(t[u].wson,top);
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==t[u].fa||v==t[u].wson) continue;
        dfs2(v,v);
    }
}

long long sum[400010];//线段树维护区间和
void build(int x,int l,int r)
{
    if(l==r)
    {
        sum[x]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    sum[x]=sum[x<<1]+sum[x<<1|1];
}
long long quesum(int x,int l,int r,int ql,int qr)
{
    if(qr<ql) return 0;
    if(ql<=l&&r<=qr) return sum[x];
    int mid=l+r>>1;
    long long ans=0;
    if(ql<=mid) ans+=quesum(x<<1,l,mid,ql,qr);
    if(qr>mid) ans+=quesum(x<<1|1,mid+1,r,ql,qr);
    return ans;
}

long long dist(int u,int v)
{
    long long ans=0;
    while(t[u].top!=t[v].top)
    {
        if(t[t[u].top].dep<t[t[v].top].dep) std::swap(u,v);
        ans+=quesum(1,1,n,t[t[u].top].id,t[u].id);
        u=t[t[u].top].fa;
    }
    if(t[u].id>t[v].id) std::swap(u,v);
    ans+=quesum(1,1,n,t[u].id+1,t[v].id);
    return ans;
}

int kth(int ss,int tt,int k)//要区分起点和终点
{
    int num=0;
    int u=ss,v=tt;//先跳一遍找到总的点数
    while(t[u].top!=t[v].top)
    {
        if(t[t[u].top].dep<t[t[v].top].dep) std::swap(u,v);
        num+=t[u].id-t[t[u].top].id+1;//这条重链
        u=t[t[u].top].fa;
    }
    if(t[u].id>t[v].id) std::swap(u,v);
    num+=t[v].id-t[u].id+1;
    while(t[ss].top!=t[tt].top)//跳链找答案
    {
        if(t[t[ss].top].dep<t[t[tt].top].dep)//跳tt点
        {
            int temp=t[tt].id-t[t[tt].top].id+1;//重链长度
            if(num-temp<k)//跳过了
            {
                return mp[t[tt].id-(num-k)];
            }
            else//还在上方,num减少
            {
                num-=temp;
                tt=t[t[tt].top].fa;
            }
        }
        else//跳ss点
        {
            int temp=t[ss].id-t[t[ss].top].id+1;
            if(k<=temp)//找到了
            {
                return mp[t[ss].id-k+1];
            }
            else//还在上方
            {
                k-=temp;
                num-=temp;
                ss=t[t[ss].top].fa;
            }
        }
    }
    //跳到同一条链上了。
    if(t[ss].dep<t[tt].dep)
        return mp[t[ss].id+k-1];
    else
        return mp[t[ss].id-k+1];
}

int main()
{
    //freopen("test.in","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(head,0,sizeof(int)*(n+2));
        cnt=id=1;
        for(int i=1,u,v,w;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        dfs1(0,1,0);
        dfs2(1,1);
        build(1,1,n);
        while(1)
        {
            char opt[10];
            int u,v,k;
            scanf("%s",opt);//开始我写了个%s%d%d,opt,&u,&v……
            if(opt[1]=='I')
            {
                scanf("%d%d",&u,&v);
                printf("%lld\n",dist(u,v));
            }
            else if(opt[1]=='T')
            {
                scanf("%d%d%d",&u,&v,&k);
                printf("%d\n",kth(u,v,k));
            }
            else break;
        }
        puts("");//空行加不加都可以A
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/wawcac-blog/p/11320522.html