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]可能会 >
可以看看这个帖子 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 谢谢两位,我改一改