Description

Solution

标算我并不会...

考虑一种根号思想

首先以 \(1\) 为根dfs整棵树

那么在任意时刻一个点的儿子的权值种类最多只会有 \(\sqrt m\) 种。

可以在每个点维护一个邻接表,存储这个点的儿子们的所有权值种类,以及该权值出现次数。

考虑如何支持修改

如果要对点 \(x\) 进行修改

首先要改它的父亲 \(fa\),就要找到它父亲的父亲 \(y\) ,因为 \(fa\) 是 \(y\) 的儿子,\(fa\) 的信息储存在了 \(y\) 邻接表里。

具体是在 \(y\) 的邻接表中找到 \(fa\) 当前的权值 \(val\),然后把这个点的出现次数 \(-1\)。再把 \(val+1\) 的出现次数 \(+1\)。这样就完成了对 \(fa\) 权值的修改。

然后改点 \(x\) 的所有儿子就比较方便了,直接遍历 \(x\) 的邻接表,把所有点的权值 \(+1\) 就好了。

看上去就做完了,但是我们还不能支持查询任意一个点当前的权值。因为邻接表存的是一个个"等价类",是无法区分具体的点的。

所以我们还需要在每个点维护两个标记方便我们快速知道真正的点权,具体是维护 \(tag[i],tag2[i]\) 分别表示修改过点 \(i\) 的儿子们多少次和点 \(i\) 的儿子们修改过多少次。这样 \(tag[i]+tag2[i]\) 就是点 \(i\) 的真实权值了。

时间复杂度 \(O(m\sqrt m)\) 但远远达不到上界。

还跑了个rank1

Code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
const int N=5e5+5;
const ll mod=1000109107; ll tot=0;
int tag[N],tag2[N];
int n,m,son[N],fa[N]; struct Edge{
int to,nxt,sze;
}; struct G{
int dp[N],dc;
int head[N],cnt;
Edge edge[N*20]; void del(int x){
dp[++dc]=x;
} int newnode(){
return dc?dp[dc--]:++cnt;
} void add(int x,int y,int z=0){
int t=newnode();
edge[t].to=y;
edge[t].nxt=head[x];
edge[t].sze=z;
head[x]=t;
} }A,B; int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
} void dfs(int now){
for(int i=A.head[now];i;i=A.edge[i].nxt){
int to=A.edge[i].to;
if(to==fa[now]) continue;
fa[to]=now;son[now]++;
dfs(to);
}
} signed main(){
freopen("cactus.in","r",stdin);freopen("cactus.out","w",stdout);
n=getint(),m=getint();
for(int i=1;i<n;i++){
int x=getint(),y=getint();
A.add(x,y),A.add(y,x);
} dfs(1);
fa[1]=n+1;son[n+1]=1;
for(int i=1;i<=n+1;i++)
if(son[i])
B.add(i,0,son[i]);
for(int cas=1;cas<=m;cas++){
int x=getint(),ans=0;
if(x>1){
int y=fa[fa[x]],val=tag[y]+tag2[fa[x]];
for(int las=0,i=B.head[y];i;las=i,i=B.edge[i].nxt){
if(B.edge[i].to==val){
if(B.edge[i].sze>1)
B.edge[i].sze--;
else if(las)
B.edge[las].nxt=B.edge[i].nxt,B.del(i);
else
B.head[y]=B.edge[i].nxt,B.del(i);
break;
}
} ans=val+1;
int flag=0;
for(int i=B.head[y];i;i=B.edge[i].nxt){
if(B.edge[i].to==ans){
B.edge[i].sze++;
flag=1; break;
}
} if(!flag)
B.add(y,ans,1);
} for(int i=B.head[x];i;i=B.edge[i].nxt){
B.edge[i].to++;
if(B.edge[i].sze&1) ans^=B.edge[i].to;
} (tot+=1ll*ans*((1ll*cas*cas%mod+cas)%mod)%mod)%=mod;
tag[x]++;tag2[fa[x]]++;
} printf("%lld\n",tot);
return 0;
}

[JZOJ5984] 仙人掌的更多相关文章

  1. jzoj5984. 【北大2019冬令营模拟2019.1.1】仙人掌 (分块)

    题面 题解 数据结构做傻了.jpg 考虑每一个节点,它的儿子的取值最多只有\(O(\sqrt {m})\)种,那么可以用一个双向链表维护儿子的所有取值以及该取值的个数,那么对儿子节点修改一个值就是\( ...

  2. bzoj1023: [SHOI2008]cactus仙人掌图

    学习了一下圆方树. 圆方树是一种可以处理仙人掌的数据结构,具体见这里:http://immortalco.blog.uoj.ac/blog/1955 简单来讲它是这么做的:用tarjan找环,然后对每 ...

  3. 【BZOJ 1023】【SHOI 2008】cactus仙人掌图

    良心的题解↓ http://z55250825.blog.163.com/blog/static/150230809201412793151890/ tarjan的时候如果是树边则做树形DP(遇到环就 ...

  4. 【BZOJ-1952】城市规划 [坑题] 仙人掌DP + 最大点权独立集(改)

    1952: [Sdoi2010]城市规划 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 73  Solved: 23[Submit][Status][ ...

  5. 【BZOJ-4316】小C的独立集 仙人掌DP + 最大独立集

    4316: 小C的独立集 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 57  Solved: 41[Submit][Status][Discuss] ...

  6. 仙人掌(cactus)

    仙人掌(cactus) Time Limit:1000ms Memory Limit:64MB 题目描述 LYK 在冲刺清华集训(THUSC) !于是它开始研究仙人掌,它想来和你一起分享它最近研究的 ...

  7. 【bzoj1023】仙人掌图

    [bzoj1023]仙人掌图 题意 给一棵仙人掌,求直径. \(n\leq 100000\) 分析 分析1:[Tarjan]+[环处理+单调队列优化线性dp]+[树形dp] 分开两种情况处理: ①环: ...

  8. hdu3594 强连通(仙人掌图)

    题意:给定一张有向图,问是否是仙人掌图.仙人掌图的定义是,首先,这张图是一个强连通分量,其次所有边在且仅在一个环内. 首先,tarjan可以判强连通分量是否只有一个.然后对于所有边是否仅在一个环内,我 ...

  9. 【BZOJ】【1023】【SHOI2008】cactus仙人掌图

    DP+单调队列/仙人掌 题解:http://hzwer.com/4645.html->http://z55250825.blog.163.com/blog/static/150230809201 ...

随机推荐

  1. 创建.NET core的守护进程

    http://www.cnblogs.com/savorboard/p/dotnetcore-supervisor.html

  2. C#部分试题实例

    1.在C#中,下列选项中自定义方法的语句错误的是().(选择一项) 正确答案:AD 解析:本题考查自定义方法的定义及调用.A项void是无返回值类型,D项定义方法的时候没有写返回值类型:故选AD. 2 ...

  3. # 2019-2020-3 《Java 程序设计》第五周学习总结

    2019-2020-3 <Java 程序设计>第五周知识总结 1.使用interface来定义一个接口.接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两 ...

  4. 2.3.7synchronized代码块有volatile同步的功能

    关键字synchronized可以使多个线程访问同一个资源具有同步性,而且他还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能. package com.cky.thread; /** * ...

  5. mysql 存储过程 CONCAT 字符串拼接

    mysql 存储过程 CREATE PROCEDURE pro_province_report (IN startDate VARCHAR(),IN endDate VARCHAR(),IN Sour ...

  6. git 命令(基础篇)的本质理解

    主要命令 1. 提交,git commit 本质:创建一个节点(node),标志了当前位置(node)与以前的node存在不同之处,如下图中的 c0 <-- c1 <-- c2 等等 图中 ...

  7. Java中List, Integer[], int[]的相互转换

    import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Mai ...

  8. php使用curl模拟登录带验证码的网站[开发篇]

    需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...

  9. Calling Functions With Pointer Parameters

     参数类型是Constant Pointer 也就是 UnsafePointer<Type> 可以传入的类型: UnsafePointer<Type>/UnsafeMutab ...

  10. Python Socket请求网站获取数据

     Python Socket请求网站获取数据 ---阻塞 I/O     ->收快递,快递如果不到,就干不了其他的活 ---非阻塞I/0 ->收快递,不断的去问,有没有送到,有没有送到,. ...