hdu 4776 Ants 杭州现场赛G题

杭州现场赛的题目,首先求出每个节点到根节点的xor值,那么两个节点路径的xor值就等于他们到根节点的xor值再xor。

那么就会有n*n个xor值,但是题目值要求前面的k个,并且k小于200000.

那么就可以这么搞了,先找xor之后最高位为1的,看看有多少个,如果大于k,那么证明前k大的全部在里面,再找次高位的就可以,否者,把这些数全部找出来并排序,剩下的再在这一位不为一的那里找。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2e5+9;
int n,m,k;
int head[maxn],lon;
long long d[maxn];
long long a[maxn<<1];
int lona;
int end;
struct
{
    int next,to;
    long long w;
}e[maxn<<1];

struct
{
    long long l1,r1;
    long long l2,r2;
}data[2][11111111];


void edgemake(int from,int to,long long w)
{
    e[++lon].to=to;
    e[lon].w=w;
    e[lon].next=head[from];
    head[from]=lon;
}
void edgeini()
{
    memset(head,-1,sizeof(head));
    lon=-1;
}

void dfs(int t,int from)
{
    for(int k=head[t];k!=-1;k=e[k].next)
    {
        int u=e[k].to;
        if(u==from) continue;
        d[u]=d[t]^e[k].w;
        dfs(u,t);
    }
}

int get(int l,int r,int x)
{
    long long tmp=(long long)1<<x;

    for(int i=r;i>=l;i--)
    if(d[i]&tmp) return i;
    return l-1;
}

long long x[11111111],y[11111111];
void bfs(int tmp,int now)
{
    long long sum=0;
    for(int i=1;i<=end;i++)
    {
        x[i]=get(data[now][i].l1,data[now][i].r1,tmp-1);
        y[i]=get(data[now][i].l2,data[now][i].r2,tmp-1);
        sum+=(x[i]-data[now][i].l1+1)*(data[now][i].r2-y[i]);
        sum+=(data[now][i].r1-x[i])*(y[i]-data[now][i].l2+1);
    }

//    printf("%d %d\n",x[1],y[1]);
//    printf("%I64d %I64d\n",data[now][1].l1,data[now][1].r1);

    if(sum<=k)
    {
        k-=sum;
        for(int i=1;i<=end;i++)
        {
            for(int p=data[now][i].l1;p<=x[i];p++)
            for(int q=y[i]+1;q<=data[now][i].r2;q++)
            a[++lona]=d[p]^d[q];
            for(int p=x[i]+1;p<=data[now][i].r1;p++)
            for(int q=data[now][i].l2;q<=y[i];q++)
            a[++lona]=d[p]^d[q];
        }
        sort(a+lona-sum+1,a+lona+1,greater<long long>());

        int top=end;
        end=0;
        int to=now^1;
        for(int i=top;i>=1;i--)
        {
            if(x[i]>=data[now][i].l1&&y[i]>=data[now][i].l2)
            {
                data[to][++end].l1=data[now][i].l1;
                data[to][end].r1=x[i];
                data[to][end].l2=data[now][i].l2;
                data[to][end].r2=y[i];
            }
            if(x[i]+1<=data[now][i].r1&&y[i]+1<=data[now][i].r2)
            {
                data[to][++end].l1=x[i]+1;
                data[to][end].r1=data[now][i].r1;
                data[to][end].l2=y[i]+1;
                data[to][end].r2=data[now][i].r2;
            }
        }
    }
    else
    {
        int top=end;
        end=0;
        int to=now^1;
        for(int i=top;i>=1;i--)
        {
            if(x[i]>=data[now][i].l1&&y[i]+1<=data[now][i].r2)
            {
                data[to][++end].l1=data[now][i].l1;
                data[to][end].r1=x[i];
                data[to][end].l2=y[i]+1;
                data[to][end].r2=data[now][i].r2;
            }
            if(x[i]+1<=data[now][i].r1&&y[i]>=data[now][i].l2)
            {
                data[to][++end].l1=x[i]+1;
                data[to][end].r1=data[now][i].r1;
                data[to][end].l2=data[now][i].l2;
                data[to][end].r2=y[i];
            }
        }
    }
}

void solve()
{
    lona=0;
    d[1]=0;
    dfs(1,-1);
    sort(d+1,d+1+n,greater<long long>());

    end=1;
    data[0][end].l1=1;
    data[0][end].r1=n;
    data[0][end].l2=1;
    data[0][end].r2=n;
    for(int i=62;i>=1;i--)
    {
        bfs(i,i&1);
        if(k==0) break;
    }
    if(k>0)
    {
        long long tmp=d[data[0][1].l1]^d[data[0][1].l2];
        while(k>0)
        {
            a[++lona]=tmp;
            k--;
        }
    }
}

int qry[maxn];
int main()
{
//    freopen("in.txt","r",stdin);
    while(scanf("%d",&n),n)
    {
        edgeini();
        for(int i=1,from,to;i<n;i++)
        {
            long long w;
            scanf("%d%d%I64d",&from,&to,&w);
            edgemake(from,to,w);
            edgemake(to,from,w);
        }
        scanf("%d",&m);
        k=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&qry[i]);
            k=max(k,qry[i]);
        }
        solve();
        long long maxm=(long long)n*(n-1);
        for(int i=1;i<=m;i++)
        {
            if(qry[i]<=maxm)
            printf("%I64d\n",a[qry[i]]);
            else
            printf("-1\n");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值