zoukankan      html  css  js  c++  java
  • P3806 离线多次询问 树上距离为K的点对是否存在 点分治

    询问树上距离为k的点对是否存在

    直接n^2暴力处理点对 桶排记录 可以过

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXN = 1e5 + 5;
    const int MAXM = 1e5 + 5;
    int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], ed = 1;
    int cost[MAXM << 1];
    int ok[10000005];
    inline void addedge(int u, int v, int c) {
            to[++ed] = v;
            cost[ed] = c;
            nxt[ed] = Head[u];
            Head[u] = ed;
    }
    inline void ADD(int u, int v, int c) {
            addedge(u, v, c);
            addedge(v, u, c);
    }
    int n, m, k;
    int sz[MAXN], f[MAXN], dep[MAXN], sumsz, root;
    bool vis[MAXN];
    int o[MAXN], cnt;
    void getroot(int x, int fa) {
            sz[x] = 1;
            f[x] = 0;
            for (int i = Head[x]; i; i = nxt[i]) {
                    int v = to[i];
                    if (v == fa || vis[v]) {
                            continue;
                    }
                    getroot(v, x);
                    sz[x] += sz[v];
                    f[x] = max(f[x], sz[v]);
            }
            f[x] = max(f[x], sumsz - sz[x]);
            if (f[x] < f[root]) {
                    root = x;
            }
    }
    void getdeep(int x, int fa) {
            o[++cnt] = dep[x];
            for (int i = Head[x]; i; i = nxt[i]) {
                    int v = to[i];
                    if (v == fa || vis[v]) {
                            continue;
                    }
                    dep[v] = dep[x] + cost[i];
                    getdeep(v, x);
            }
    }
    void calc(int x, int d, int add) {
            cnt = 0;
            dep[x] = d;
            getdeep(x, 0);
            sort(o + 1, o + cnt + 1);
            for (int i = 1; i <= cnt; i++) {
                    for (int j = i + 1; j <= cnt; j++) {
                            ok[o[i] + o[j]] += add;
                    }
            }
    }
    void solve(int x) {
            calc(x, 0, 1);
            vis[x] = 1;
            for (int i = Head[x]; i; i = nxt[i]) {
                    int v = to[i];
                    if (vis[v]) {
                            continue;
                    }
                    calc(v, cost[i], -1);
                    root = 0, sumsz = sz[v];
                    getroot(v, 0);
                    solve(root);
            }
    }
    int main() {
            scanf("%d %d", &n, &m);
            cnt = 0;
            memset(Head, 0, sizeof(Head));
            memset(vis, 0, sizeof(vis));
            memset(ok, 0, sizeof(ok));
            ed = 1;
            int u, v, c;
            for (int i = 1; i < n; i++) {
                    scanf("%d %d %d", &u, &v, &c);
                    ADD(u, v, c);
            }
            root = 0, sumsz = f[0] = n;
            getroot(1, 0);
            solve(root);
            for (int i = 1; i <= m; i++) {
                    scanf("%d", &k);
                    if (ok[k]) {
                            printf("AYE
    ");
                    } else {
                            printf("NAY
    ");
                    }
            }
            return 0;
    }
    View Code

    用类似poj1741的方法:对于每一次询问 calc()函数中求出<=k的和>=k的数量再减去总对数 则为=k的数量

    复杂度为O(m*n*log2n)

    #include<bits/stdc++.h>
    #define MAXN 10005
    #define INF 1e9+7
    using namespace std;
    struct front_star{
        int to,next,w;
    }edge[MAXN<<1];
    int n,cnt=0,k,mx,root,ans=0,tot=1,siz,m;
    int head[MAXN],sz[MAXN],temp[MAXN],idx[MAXN];
    bool vis[MAXN];
    int maxn(int a,int b)
    {
        return a>b?a:b;
    }
    void addedge(int u,int v,int c)
    {
        cnt++;
        edge[cnt].to=v;
        edge[cnt].w=c;
        edge[cnt].next=head[u];
        head[u]=cnt;
    }
    void findroot(int u,int fa)
    {
        sz[u]=1;
        int msz=0;
        for(int i=head[u];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(v!=fa&&!vis[v])
                   {
                      findroot(v,u); 
                      sz[u]+=sz[v];
                      msz=maxn(msz,sz[v]);     
                   }
            }
        msz=maxn(msz,siz-sz[u]);
        if(msz<mx)
           {
               mx=msz;
               root=u;
           }       
    }
    void init()
    {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n-1;i++)
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                addedge(a,b,c);
                addedge(b,a,c);
            }
    }
    void dist(int u,int fa)
    {
        for(int i=head[u];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(!vis[v]&&v!=fa)
                   {
                       tot++;
                       idx[v]=tot;
                       temp[tot]=temp[idx[u]]+edge[i].w;
                       dist(v,u);
                   }
            }
    }
    int count_ans(int u,int val)
    {
        tot=1;
        idx[u]=1;
        temp[1]=val;
        dist(u,u);
        sort(temp+1,temp+1+tot);
        int L=1,R=tot,res1=0,res2=0,ret;
        while(L<=R)
              {
                   if(temp[L]+temp[R]<=k)
                      {
                          res1+=R-L;
                          L++;
                      }
                   else
                      R--;
              }
        L=1,R=tot;      
        while(L<=R)
              {
                   if(temp[L]+temp[R]>=k)
                      {
                           res2+=R-L;
                           R--;
                      }
                   else
                      L++;   
              } 
        ret=res1+res2-(tot*(tot-1))/2; 
        return ret;     
    }
    void divide(int u)
    {
        ans+=count_ans(u,0);
        vis[u]=true;
        for(int i=head[u];~i;i=edge[i].next)
            {
                int v=edge[i].to;
                if(!vis[v]&&!vis[v])
                   {
                        ans-=count_ans(v,edge[i].w);
                        siz=sz[v];
                        mx=INF;
                        findroot(v,u);
                        divide(root);  
                   }
            }
    }
    void query()
    {
        for(int i=1;i<=m;i++)
            {
                memset(vis,false,sizeof(vis));
                scanf("%d",&k);
                siz=n;
                mx=INF;
                ans=0;
                findroot(1,1);
                divide(root);
                if(ans==0)
                   printf("NAY
    ");
                else
                   printf("AYE
    ");   
            }
    }
    int main()
    {
        init();
        query();
        return 0;
    }
    View Code
  • 相关阅读:
    springboot -jar部署
    base64前端对登陆密码编码,后端解码
    数字择优( 计算一个数与一组数字中的哪一个数字大小最接近)
    求两个数组的最小差值
    url.openConnection()远程获取图片缺失
    HttpURLConnection 用法详解
    Eureka集群入门搭建
    Django基础(五)- form组件及django序列化
    django基础(四)- 分页组件
    Django基础(四)-cookie与session
  • 原文地址:https://www.cnblogs.com/Aragaki/p/10476108.html
Copyright © 2011-2022 走看看