点分治被卡得厉害,这是被卡死了还是我写假了

P3806 【模板】点分治 1

woshiren @ 2020-05-18 18:24:45

我的思路是先离线,然后点分治处理 calc使用了两种方式都没有过,第一种是双指针,第二种是开桶,看起来效率没有差别,求各位dalao帮忙看看。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct data
{
    int to,val,next;
}edge[20005];
const int inf=15000005;
int root,cnt,rmb[10005],q[10005],head[10005],a[10005],tot,belong[10005],ans[10005],rec[105],u,v,w,n,m,size[10005],recsize=0x3f3f3f3f,dis[10005],vis[10005];
bool flag[inf];
void add(int u,int v,int w)
{
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    edge[cnt].val=w;
    head[u]=cnt;
}
void get_root(int u,int fa)
{
    int maxsize=0;
    size[u]=1;
    for (int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if (v==fa||vis[v]) continue;
        get_root(v,u);
        size[u]+=size[v];
        maxsize=max(size[v],maxsize);
    }
    maxsize=max(maxsize,n-size[u]);
    if (maxsize<recsize)
    {
        root=u;
        recsize=maxsize;
    }
}
void dfs(int now,int rt,int fa)
{
    //a[++tot]=now;
    //belong[now]=cnt;
    rmb[++rmb[0]]=dis[now];
    for (int i=head[now];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if (v==fa||vis[v]) continue;
        //if (now==rt) cnt++;
        dis[v]=dis[now]+edge[i].val;
        dfs(v,rt,now);
    }
}
void calc()
{
    /*for (int i=1;i<=m;i++)
    {
        int k=rec[i],l=1,r=tot;
        if (ans[i]) continue;
        while (l<r)
        {
            if (dis[a[l]]+dis[a[r]]>k) r--;
            else if (dis[a[l]]+dis[a[r]]<k) l++;
            else if (dis[a[l]]+dis[a[r]]==k&&belong[a[l]]==belong[a[r]])
                {
                    if (dis[a[r]]==dis[a[r-1]]) r--;
                    else l++;
                }
            else 
            {
                ans[i]=true;
                break;
            }
        }
    }*/
    int p=0;
    for (int i=head[root];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if (vis[v]) continue;
        rmb[0]=0;dis[v]=edge[i].val;
        dfs(v,root,root);
        for (int j=rmb[0];j;j--)
            for (int k=1;k<=m;k++)
                if (rec[k]>=rmb[j]) ans[k]|=flag[rec[k]-rmb[j]];
        for (int j=rmb[0];j;j--)
            q[++p]=rmb[j],flag[rmb[j]]=true;
    }       
    for (int i=1;i<=p;i++)
        flag[q[i]]=false;
}
bool cmp(int x,int y)
{
    return dis[x]<dis[y];
}
void work()
{
    cnt=0;dis[root]=0;tot=0;vis[root]=true;
    flag[0]=1;
    //dfs(root,root,0);
    //sort(a+1,a+1+tot,cmp);
    calc();
    int t=root;
    for (int i=head[t];i;i=edge[i].next)
    {
        if (vis[edge[i].to]) continue;
        recsize=0x3f3f3f3f;
        get_root(edge[i].to,t);
        work();
    }
}
int read()
{
    char c=getchar();int num=0;
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9') {num*=10;num+=c-48;c=getchar();}
    return num;
}
int main()
{
    n=read();m=read();
    for (int i=1;i<n;i++)
    {
        u=read(),v=read(),w=read();
        add(u,v,w);add(v,u,w);
    }
    for (int i=1;i<=m;i++)
    {
        int k;
        k=read();
        rec[i]=k;
    }
    get_root(1,0);
    work();
    for (int i=1;i<=m;i++)
        printf(ans[i]?"AYE\n":"NAY\n");
    return 0;
}

by IOI2021 @ 2020-05-18 18:31:47

好像是代码中的这一段

 for (int j=rmb[0];j;j--)
    q[++p]=rmb[j],flag[rmb[j]]=true;

rmb[j]可能会 > 10^7

可以看看这个帖子 https://www.luogu.com.cn/discuss/show/188596

加油!


by TLE自动机 @ 2020-05-18 18:51:50

大括号换行邪教!


by FZzzz @ 2020-05-18 18:58:08

@woshiren 您的重心是假的


by IOI2021 @ 2020-05-18 19:01:44

您找的是全局重心啊,明显会TLE,要找子树内的重心啊


by woshiren @ 2020-05-18 20:50:36

@IOI2019 @FZzzz 谢谢两位,我改一改


|