zoukankan      html  css  js  c++  java
  • 《洛谷P3806》

    也是点分治的简单题。(对我来说算难了orz.)

     首先这里的难点就在于查询是否存在长度k。

    如果我们每次都去对询问进行一次点分治,显然是过于浪费了。

    所以我们可以离线做它。

    在点分治过程中统计所有答案。

    那么怎么统计答案,又是一大难点,如果要直接按之前找k点对的统计。

    那么容斥删点的时候,需要找遍所有的组合,复杂度就到了n^2.显然不行。

    这里就采用了新的思路,不再容斥。

    我们对每个点是在哪个子节点的下面都做一个标记,然后再去统计即可。

    如果在同一个子节点里,说明不合法。

    然后对每个询问都进行一次类似二分的查询即可。

    复杂度应该接近nlogn

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1e4+5;
    const int M = 1e7+5;
    const LL Mod = 1e9+7;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define CT0 cin.tie(0),cout.tie(0)
    #define IO ios::sync_with_stdio(false)
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){  
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
        void print(int x){
            if(x < 0){x = -x;putchar('-');}
            if(x > 9) print(x/10);
            putchar(x%10+'0');
        }
    }
    using namespace FASTIO;
    void FRE(){
    /*freopen("data1.in","r",stdin);
    freopen("date1.out","w",stdout);*/}
    
    int n,m,cnt = 0,head[N],ask[105],vis[N],ssize[N],mx = INF,rt,sz = n,tot = 0,val[105];
    int dis[N],a[N],b[N];//dis[i]距离i的距离,a[i]i哪个点,b[i]-i为在哪个子节点
    struct Node{int to,dis,next;}e[N<<1];
    inline void add(int u,int v,int w)
    {
        e[++cnt].to = v,e[cnt].dis = w,e[cnt].next = head[u],head[u] = cnt;
    }
    bool cmp(int a,int b)
    {
        return dis[a] < dis[b];
    }
    void Findroot(int u,int fa)
    {
        ssize[u] = 1;
        int son = 0;
        for(rg int i = head[u];i;i = e[i].next)
        {
            int v = e[i].to,d = e[i].dis;
            if(v == fa || vis[v]) continue;
            Findroot(v,u);
            ssize[u] += ssize[v];
            son = max(son,ssize[v]);
        }
        son = max(son,sz-ssize[u]);
        if(son < mx) mx = son,rt = u;
    }
    void Dis_slove(int u,int fa,int root,LL z)
    {
        a[++tot] = u;
        dis[u] = z;
        b[u] = root;
        for(rg int i = head[u];i;i = e[i].next)
        {
            int v = e[i].to,d = e[i].dis;
            if(v == fa || vis[v]) continue;
            Dis_slove(v,u,root,z+d);
        }
    }
    void slove(int u)
    {
        tot = 0;
        a[++tot] = u;
        dis[u] = 0;
        b[u] = u;
        for(rg int i = head[u];i;i = e[i].next)
        {
            int v = e[i].to,d = e[i].dis;
            if(vis[v]) continue;
            Dis_slove(v,u,v,d);
        }
        sort(a+1,a+tot+1,cmp);
        for(rg int i = 1;i <= m;++i)
        {
            if(ask[i]) continue;
            int L = 1,r = tot;
            while(L < r)
            {
                if(dis[a[L]]+dis[a[r]] > val[i]) r--;
                else if(dis[a[L]]+dis[a[r]] < val[i]) L++;
                else//长度相等
                {
                    if(b[a[L]] == b[a[r]])//如果两个点都属于同一子节点,那么关于L的查询已经结束,因为L不可能再有了,所以移动L,但是如果r-1=r,那么r-1也不用查询了,直接移动r
                    {
                        if(dis[a[r]] == dis[a[r-1]]) r--;//
                        else L++;
                    }
                    else{ask[i] = 1;break;}
                }
            }
        }
    }
    void divide(int u)
    {
        slove(u);
        vis[u] = 1;
        for(rg int i = head[u];i;i = e[i].next)
        {
            int v = e[i].to,d = e[i].dis;
            if(vis[v]) continue;
            sz = ssize[v],mx = INF;
            Findroot(v,0);
            divide(rt);
        }
    }
    int main()
    {
        n = read(),m = read();
        for(rg int i = 1;i < n;++i)
        {
            int u,v,w;
            u = read(),v = read(),w = read();
            add(u,v,w);add(v,u,w);
        }
        for(rg int i = 1;i <= m;++i) 
        {
            val[i] = read();
            if(val[i] == 0) ask[i] = 1;
        }
        Findroot(1,0);
        divide(rt);
        for(rg int i = 1;i <= m;++i) printf("%s
    ",ask[i] ? "AYE" : "NAY");
        system("pause");     
        return 0;
    }
    View Code
  • 相关阅读:
    linux sort,uniq,cut,wc命令详解
    Linux IO实时监控iostat命令详解
    uniq命令
    四层和七层负载均衡的区别
    keepalived 和 heartbeat对比
    LVS+Keepalived实现负载均衡
    Lvs+heartbeat高可用高性能web站点的搭建
    使用 awk 过滤文本或文件中的字符串
    最全mysql的复制和读写分离
    伤不起
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13571152.html
Copyright © 2011-2022 走看看