• 题目链接:

    https://www.luogu.org/problemnew/show/P4092

  • 瞎扯--\(O(Q \log^3 N)\)解法

    这道先yy出了一个\(O(Q \log^3 N)\),的做法,先树链剖分。

    对于加标记操作,找到那个点所在的链,将其\(top\)标记一下,然后该点到根节点区间和+1.

    对于查询操作,先看这个点所在链有没有标记,如果没有,就一直向上跳直到找到一条标记了的链,然后在那条链上根据到根节点区间和进行倍增/二分

    然后出去吃饭的时候忽然想到了\(O(Q \log^2 N)\)的解法,于是刚刚这个解法刚打完还没有查错,放在这做一个参考

    代码:

include

include

include

include

include

include

include

define ll long long

define ri register int

using namespace std;

const int maxn=100005;

const int inf=0x7fffffff;

template inline void read(T &x){

x=0;int ne=0;char c;

while(!isdigit(c=getchar()))ne=c'-';

x=c-48;

while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;

x=ne?-x:x;

return ;

}

int n,q;

struct Edge{

int ne,to;

}edge[maxn<<1];

int h[maxn],num_edge=0;

inline void add_edge(int f,int t){

edge[++num_edge].ne=h[f];

edge[num_edge].to=t;

h[f]=num_edge;

return ;

}

int dep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],dfn[maxn],rnk[maxn],cnt=0;

void dfs_1(int now){

int v;size[now]=1;

for(ri i=h[now];i;i=edge[i].ne){

v=edge[i].to;

if(vfa[now])continue;

fa[v]=now,dep[v]=dep[now]+1;

dfs_1(v);

size[now]+=size[v];

if(!son[now]||size[son[now]]<size[v])son[now]=v;

}

return ;

}

void dfs_2(int now,int t){

int v;top[now]=t;

dfn[now]=++cnt,rnk[cnt]=now;

if(!son[now])return ;

dfs_2(son[now],t);

for(ri i=h[now];i;i=edge[i].ne){

v=edge[i].to;

if(vfa[now]||vson[now])continue;

dfs_2(v,v);

}

return ;

}

int sum[maxn<<2],tag[maxn<<2],L,R,dta,ok[maxn];

void build(int now,int l,int r){

if(lr){

sum[now]=ok[rnk[l]];

return ;

}

int mid=(l+r)>>1;

build(now<<1,l,mid);

build(now<<1|1,mid+1,r);

return ;

}

void pushdown(int now,int ln,int rn){

if(tag[now]){

sum[now<<1]+=tag[now]ln;

sum[now<<1|1]+=tag[now]
rn;

tag[now<<1]+=tag[now];

tag[now<<1|1]+=tag[now];

tag[now]=0;

}

return ;

}

void update(int now,int l,int r){

if(L<=l&&r<=R){

sum[now]+=dta*(r-l+1);

tag[now]+=dta;

return ;

}

int mid=(l+r)>>1;

pushdown(now,mid-l+1,r-mid);

if(L<=mid)update(now<<1,l,mid);

if(mid<R)update(now<<1|1,mid+1,r);

sum[now]=sum[now<<1]+sum[now<<1|1];

return ;

}

int query(int now,int l,int r){

if(L<=l&&r<=R){

return sum[now];

}

int mid=(l+r)>>1,ans=0;

pushdown(now,mid-l+1,r-mid);

if(L<=mid)ans+=query(now<<1,l,mid);

if(mid<R)ans+=query(now<<1|1,mid+1,r);

sum[now]=sum[now<<1]+sum[now<<1|1];

return ans;

}

void update_path(int x,int y){

dta=1;ok[top[x]]=1;//该条链上有一个标记的点

while(top[x]!=top[y]){

if(dep[top[x]]<dep[top[y]])swap(x,y);

L=dfn[top[x]],R=dfn[x];

update(1,1,n);

}

if(dfn[x]<dfn[y])swap(x,y);

L=dfn[x],R=dfn[y];

update(1,1,n);

return ;

}

inline int solve(int x,int y){

int tmp,val,p=0,k=1,len,ans=0;

bool flag=0;

while(top[x]!=top[y]){

if(dep[top[x]]<dep[top[y]])swap(x,y);

len=dfn[x]-dfn[top[x]];

if(ok[top[x]]){

L=dfn[top[x]],R=dfn[x],

tmp=query(1,1,n);

p=0,k=1,flag=0;

while(k!=0){

L=dfn[x+p+k],R=dfn[x];

if(query(1,1,n)>tmp)flag=1,k=k>>1;

else p=p+k,k=k<<1;

while(p+k>len)k=k>>1;

}

if(flag)return ans+dfn[x+p]-dfn[x];

}

ans+=len;

x=fa[top[x]];

}

if(dfn[x]>dfn[y])swap(x,y);

L=dfn[x],R=dfn[y],len=dfn[y]-dfn[x];

tmp=query(1,1,n);

p=0,k=1;

//cout<<y<<endl;

if(xy)return ans;

while(k!=0){

L=dfn[x+p+k],R=dfn[x];

if(query(1,1,n)>tmp)k=k>>1;

else p=p+k,k=k<<1;

//if(y3)cout<<k<<' '<<p<<endl;

while(p+k>len)k=k>>1;

}

return ans+dfn[x+p]-dfn[x];

}

int main(){

char opt[5];

int x,y,z;

read(n),read(q);

for(ri i=1;i<n;i++){

read(x),read(y);

add_edge(x,y);

add_edge(y,x);

}

dep[1]=1,fa[1]=0;

dfs_1(1);

dfs_2(1,1);

ok[dfn[1]]=1;

build(1,1,n);

while(q--){

scanf("%s",opt);

if(opt[0]'C'){

read(x);

//cout<<x<<"-----"<<endl;

update_path(1,x);

}

else{

read(x);

//cout<<x<<"***"<<endl;

printf("%d\n",solve(x,1));

}

}

return 0;

}


- 分析---$O(Q \log^2 N)$解法 首先我想到了一个错误的解法,就是因为链是线段树上一个连续的区间,每个$[dfn[x],dfn[top[x]]]$线段树区间有个$mx$值,表示,$x$到$top[x]$路径中距离它最近标记的祖先,加标记时比较原有标记深度与新标记深度然后更新。查询的时候查询$x$到$top[x]$的区间最大之就可以了,如果没有,就一直往上跳直至找到 然而这个解法有个错误我SB地没有发现,就是你更新区间最大值时,$x$上的祖先节点也会被更新到(因为深度更小),再次感谢wjyyy和creed_两位大佬指出我的错误 正解应该是更新子树,将子树的最大值更新,查询照样,相比于我错误的代码只需改一句话 代码:

include

include

include

include

include

include

include

define ll long long

define ri register int

using namespace std;

const int maxn=100005;

const int inf=0x7fffffff;

template inline void read(T &x){

x=0;int ne=0;char c;

while(!isdigit(c=getchar()))ne=c'-';

x=c-48;

while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;

x=ne?-x:x;

return ;

}

int n,q;

struct Edge{

int ne,to;

}edge[maxn<<1];

int h[maxn],num_edge=0;

inline void add_edge(int f,int t){

edge[++num_edge].ne=h[f];

edge[num_edge].to=t;

h[f]=num_edge;

return ;

}

int dep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],dfn[maxn],rnk[maxn],cnt=0;

void dfs_1(int now){

int v;size[now]=0;

for(ri i=h[now];i;i=edge[i].ne){

v=edge[i].to;

if(vfa[now])continue;

fa[v]=now,dep[v]=dep[now]+1;

dfs_1(v);

size[now]+=size[v];

if(!son[now]||size[son[now]]<size[v])son[now]=v;

}

return ;

}

void dfs_2(int now,int t){

int v;top[now]=t;

dfn[now]=++cnt,rnk[cnt]=now;

if(!son[now])return ;

dfs_2(son[now],t);

for(ri i=h[now];i;i=edge[i].ne){

v=edge[i].to;

if(vfa[now]||vson[now])continue;

dfs_2(v,v);

}

return ;

}

int mx[maxn<<2],L,R,dta;

void build(int now,int l,int r){

if(lr){

if(rnk[l]1)mx[now]=1;

else mx[now]=0;

return ;

}

int mid=(l+r)>>1;

build(now<<1,l,mid);

build(now<<1|1,mid+1,r);

if(dep[mx[now<<1]]>dep[mx[now<<1|1]]){

mx[now]=mx[now<<1];

}

else mx[now]=mx[now<<1|1];

return ;

}

void update(int now,int l,int r){

if(L<=l&&r<=R){

if(dep[mx[now]]<dep[dta]){

mx[now]=dta;

}

return ;

}

int mid=(l+r)>>1;

if(L<=mid)update(now<<1,l,mid);

if(mid<R)update(now<<1|1,mid+1,r);

if(dep[mx[now<<1]]>dep[mx[now<<1|1]]){

mx[now]=mx[now<<1];

}

else mx[now]=mx[now<<1|1];

return ;

}

int query(int now,int l,int r){

if(L<=l&&r<=R){

return mx[now];

}

int mid=(l+r)>>1,ans=0,tmp;

if(L<=mid){

int tmp=query(now<<1,l,mid);

if(dep[ans]<dep[tmp])ans=tmp;

}

if(mid<R){

int tmp=query(now<<1|1,mid+1,r);

if(dep[ans]<dep[tmp])ans=tmp;

}

return ans;

}

void update_path(int x){

dta=x;

//L=R=dfn[x];

L=dfn[x],R=dfn[x]+size[x];

update(1,1,n);

return ;

}

int query_path(int x){

int ans=0;

while(top[x]!=1){

L=dfn[top[x]],R=dfn[x];

ans=query(1,1,n);

if(ans!=0)return ans;

x=fa[top[x]];

}

L=dfn[1],R=dfn[x];

ans=query(1,1,n);

return ans;

}

int main(){

char opt[5];

int x,y,z;

read(n),read(q);

for(ri i=1;i<n;i++){

read(x),read(y);

add_edge(x,y);

add_edge(y,x);

}

dep[0]=-1,dep[1]=1,fa[1]=0;

dfs_1(1);

dfs_2(1,1);

build(1,1,n);

while(q--){

//cout<<q<<endl;

scanf("%s",opt);

if(opt[0]=='C'){

read(x);

update_path(x);

}

else{

read(x);

printf("%d\n",query_path(x));

}

}

return 0;

}

```

最新文章

  1. Copy-On-Write容器
  2. http响应需要记住的状态码
  3. SharePoint安全 - 攻破SharePoint(黑客工具介绍)
  4. Eclipse插件开发之基础篇(4) OSGi框架
  5. structs 源码示例
  6. 02C#基础(1)
  7. PHPStrom上传文件报502错误原因
  8. windows apache 配置多个服务 站点 Apache Service Monitor
  9. asp下sha1加密函数
  10. 阅读spring源码
  11. 使用Task
  12. docker 构建 https 私有仓库 Registry
  13. 如何用java完成一个中文词频统计程序
  14. 在scrapy中使用mongodb管道
  15. Struts2的CRUD操作
  16. ansible(1)
  17. ceph---luminous 块存储(RBD)搭建
  18. 很好用的谷歌字体以及Gravatar头像一键替换WordPress插件----WP Acceleration for China 插件
  19. JAVA环境安装配置
  20. SpringSecurity 3.2入门(1)框架介绍

热门文章

  1. [MyBatis]org.apache.ibatis.binding.BindingException的避免
  2. react hook的todolist
  3. MySQL 创建删除和选择数据库
  4. C++ fill fill_n generate generate_n
  5. 工作流调度器之Azkaban
  6. iOS-AVFoundation实现二维码(ios7以上,转载)
  7. 移植Fatfs文件系统到工程中
  8. Ocelot 配置参数
  9. BP神经网络算法预测销量高低
  10. webdriervAPI(获取验证信息)