传送门

题意

分析

f[u]表示u到根的边的异或

树上两点之间的异或值为f[u]^f[v],

然后将查询用莫队算法分块,每个点插入到字典树中,利用字典树维护两点异或值大于等于M复杂度O(N^(3/2)*logM)

参考 _zidaoziyan

表示又陷入查错的大坑,思路是对的,调不出来,留坑

trick

代码

wa
#include <bits/stdc++.h>
using namespace std; #define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define F(i,a,b) for(int i=a;i<=b;++i) const int maxn = 50050;//集合中的数字个数
int ch[20*maxn][2];//节点的边信息
int num[20*maxn];//记录节点的使用次数,删除时要用
//int val[32*maxn];//节点存储的值
int cnt;//树中节点的个数 bitset<20>choose;
int ask;
int f[maxn],vis[maxn];
ll ans[maxn];
vector<pair<int,int> >mp[maxn];
struct node
{
int l,r,id,len;
bool operator<(const node &p)const
{
return len==p.len?r<p.r:len<p.len;
}
}a[maxn]; void bfs(int u)
{
queue<int>q;
q.push(1);
mem(vis,0);
vis[1]=1;f[1]=0;
while(!q.empty())
{
int tmp=q.front();q.pop();
for(int i=0;i<mp[tmp].size();++i)
{
int v=mp[tmp][i].first;
if(vis[v]) continue;
f[v]=f[tmp]^mp[tmp][i].second;
q.push(v);vis[v]=1;
}
}
} inline void init()
{
cnt=1;mem(ch[0],0);//清空树
}
/*
void insert(int x)//在字典树中插入x,和一般字典树操作相同,将x化成二进制插入到字典树
{
int cur=0;
for(int i=29;i>=0;--i)
{
int idx=((x>>i)&1);
if(!ch[cur][idx])
{
mem(ch[cnt],0);
num[cnt]=0;
ch[cur][idx]=cnt++;
//val[cnt++]=0;
}
//printf("ch[%d][%d]=%d\n",cur,idx,ch[cur][idx]);
cur=ch[cur][idx];
num[cur]++;
}
//val[cur]=x;//最后节点插入val
}
*/
void update(int x,int c)
{
int cur=0;
for(int i=17;i>=0;--i)
{
int idx=((x>>i)&1);
if(!ch[cur][idx])
{
mem(ch[cnt],0);
num[cnt]=0;
ch[cur][idx]=cnt++;
}
cur=ch[cur][idx];
num[cur]+=c;
}
} /*
ll query(ll x)//在字典树(数集)中查找和x异或是最大值的元素y,返回y
{
int cur=0;
for(int i=32;i>=0;--i)
{
int idx=(x>>i)&1;
if(ch[cur][idx^1]) cur=ch[cur][idx^1];else cur=ch[cur][idx];
}
return val[cur];
}
*/ int query(int x)//返回移动一位增加/减少的匹配数
//带删除操作的查询
{
int cur=0,idx,ans=0;
for(int i=17;i>=0;--i)
{
if((i<<i)&x) idx=1;else idx=0;
if(!choose[i])
{
if(ch[cur][idx^1]) ans+=num[ch[cur][idx^1]];
if((!ch[cur][idx])||(!num[ch[cur][idx]])) return ans;
cur=ch[cur][idx];
}
else
{
if((!ch[cur][idx^1])||(num[ch[cur][idx^1]]==0)) return ans;
cur=ch[cur][idx^1];
}
//printf("%d\n",ret);
//if(ch[cur][idx^1]&&num[ch[cur][idx^1]]) cur=ch[cur][idx^1];else cur=ch[cur][idx];
}
//printf("val(%d)=%d\n",cur,val[cur]);
return ans;
} /*
int get_ans(int x)
{
int cur=0,ret=0;
for(int i=29;i>=0;--i)
{
int idx=(((x>>i)&1)^1);
if(num[ch[cur][idx]]) cur=ch[cur][idx],ret|=(1<<i);
else cur=ch[cur][idx^1];
}
return ret;
}
*/
void solve()
{
int L=1,R=0;
init();
ll tmp=0;
F(i,1,ask)
{
while(R<a[i].r) {R++;tmp+=query(f[R]);update(f[R],1);}
//printf("tmp1=%lld\n",tmp);
while(R>a[i].r) {update(f[R],-1);tmp-=query(f[R]);R--;}
// printf("tmp2=%lld\n",tmp);
while(L<a[i].l) {update(f[L],-1);tmp-=query(f[L]);L++;}
// printf("tmp3=%lld\n",tmp);
while(L>a[i].l) {L--;tmp+=query(f[L]);update(f[L],1);}
//printf("tmp4=%lld\n",tmp);
//printf("%lld\n",tmp);;
ans[a[i].id]=tmp;
}
} int main()
{
int n,m;
while(scanf("%d %d %d",&n,&m,&ask)!=EOF)
{
int u,v,w,sqr=sqrt(n);choose=m;
F(i,1,n) mp[i].clear();
F(i,1,n-1)
{
scanf("%d %d %d",&u,&v,&w);
mp[u].push_back(pair<int,int>{v,w});
mp[v].push_back(pair<int,int>{u,w});
}
bfs(1);
//F(i,1,n) printf("%d%c",f[i],i==n?'\n':' ');
F(i,1,ask)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id=i;a[i].len=a[i].l/sqr;
}
sort(a+1,a+1+ask);
//F(i,1,ask) printf("%d %d %d\n",a[i].l,a[i].r,a[i].id );
solve();
F(i,1,ask) printf("%lld\n",ans[i]);
}
return 0;
}
//ac
#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
typedef pair<int,int> PI;
vector<PI>G[maxn];
int a[maxn],unit,q;
bitset <20> cnt;
int vis[maxn];
long long ans[maxn]; struct node{
int l,r,id;
}Q[maxn]; bool cmp(node u,node v){
if(u.l/unit!=v.l/unit)
return u.l/unit<v.l/unit;
return u.r<v.r;
} void bfs(int u){
queue<int>Q;
Q.push(1);
memset(vis,0,sizeof(vis));
vis[1]=1;
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(int i=0;i<G[u].size();i++){
int v=G[u][i].first;
if(vis[v])
continue;
a[v]=a[u]^G[u][i].second;
Q.push(v);
vis[v]=1;
}
}
} struct Trie{
int val[maxn*20],next[maxn*20][2];
int sz;
void init(){
sz=1;
memset(next[0],0,sizeof(next[0]));
} void insert(int num,int x){
int u=0,c;
for(int i=17;i>=0;i--){
if((1<<i)&num)
c=1;
else
c=0;
if(!next[u][c])
memset(next[sz],0,sizeof(next[sz])),val[sz]=0,next[u][c]=sz++;
u=next[u][c];
val[u]+=x;
}
} int query(int num){
int ans=0,c,u=0;
for(int i=17;i>=0;i--){
if((1<<i)&num)
c=1;
else
c=0;
if(cnt[i]==0){
if(next[u][c^1])
ans+=val[next[u][c^1]];
if(!next[u][c]||val[next[u][c]]==0)
return ans;
u=next[u][c];
}
else{
if(!next[u][c^1]||val[next[u][c^1]]==0)
return ans;
u=next[u][c^1];
}
// printf("%d\n",ans);
}
return ans;
}
}; Trie trie;
void solve(){
int L=1,R=0;
trie.init();
long long tmp=0;
for(int i=1;i<=q;i++){
while(R<Q[i].r){
R++;
tmp+=trie.query(a[R]);
trie.insert(a[R],1);
}
//printf("tmp1=%lld\n",tmp); while(R>Q[i].r){
trie.insert(a[R],-1);
tmp-=trie.query(a[R]);
R--;
}
//printf("tmp2=%lld\n",tmp);
while(L<Q[i].l){
trie.insert(a[L],-1);
tmp-=trie.query(a[L]);
L++;
}
// printf("tmp3=%lld\n",tmp );
while(L>Q[i].l){
L--;
tmp+=trie.query(a[L]);
trie.insert(a[L],1);
}
// printf("tmp4=%lld\n", tmp);
ans[Q[i].id]=tmp;
}
} int main(){
int n,m;
while(scanf("%d%d%d",&n,&m,&q)!=EOF){
int u,v,w;
for(int i=1;i<=n;i++)
G[i].clear();
for(int i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(PI{v,w});
G[v].push_back(PI{u,w});
}
cnt=m;
a[1]=0,unit=sqrt(n);
bfs(1);
// for(int i=1;i<=n;++i) printf("%d%c",a[i],i==n?'\n':' ');
for(int i=1;i<=q;i++){
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
sort(Q+1,Q+q+1,cmp);
// for(int i=1;i<=q;++i) printf("%d %d %d %d\n",Q[i].l,Q[i].r,Q[i].id);
solve();
for(int i=1;i<=q;i++)
printf("%lld\n",ans[i]);
}
return 0;
}

HDU5589:Tree(莫队+01字典树)的更多相关文章

  1. HDU5589 Tree【分块 01字典树】

    HDU5589 Tree 题意: 给出一棵\(N\)个点的树,每条边有边权,每次询问下标为\([L,R]\)区间内的点能选出多少点对,点对之间的路径上的边权异或和大于\(M\) 题解: 对于两点\(u ...

  2. HDU 6191 2017ACM/ICPC广西邀请赛 J Query on A Tree 可持久化01字典树+dfs序

    题意 给一颗\(n\)个节点的带点权的树,以\(1\)为根节点,\(q\)次询问,每次询问给出2个数\(u\),\(x\),求\(u\)的子树中的点上的值与\(x\)异或的值最大为多少 分析 先dfs ...

  3. HDU6191 Query on A Tre【dsu on tree + 01字典树】

    Query on A Tree Problem Description Monkey A lives on a tree, he always plays on this tree. One day, ...

  4. HDU6191 Query on A Tree (01字典树+启发式合并)

    题意: 给你一棵1e5的有根树,每个节点有点权,1e5个询问(u,x),问你子树u中与x异或最大的值是多少 思路: 自下而上启发式合并01字典树,注意合并时清空trie 线段树.字典树这种结构确定的数 ...

  5. HDU6191(01字典树启发式合并)

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  6. Chip Factory(01字典树)

    Chip Factory http://acm.hdu.edu.cn/showproblem.php?pid=5536 Time Limit: 18000/9000 MS (Java/Others)  ...

  7. HDU 4757 Tree(可持久化字典树)(2013 ACM/ICPC Asia Regional Nanjing Online)

    Problem Description   Zero and One are good friends who always have fun with each other. This time, ...

  8. 2014百度之星资格赛—— Xor Sum(01字典树)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total ...

  9. AcWing:144. 最长异或值路径(dfs + 01字典树)

    给定一个树,树上的边都具有权值. 树中一条路径的异或长度被定义为路径上所有边的权值的异或和: ⊕ 为异或符号. 给定上述的具有n个节点的树,你能找到异或长度最大的路径吗? 输入格式 第一行包含整数n, ...

随机推荐

  1. ZT:与其怨天尤人,不如全力以赴;若想改变世界,你必须先从改变自己开始!

    在闻名世界的威斯特敏斯特大教堂地下室的墓碑林中,有一块名扬世界的墓碑.其实这只是一块很普通的墓碑,粗糙的花岗石质地,造型也很一般,同周围那些质地上乘.做工优良的亨利三世到乔治二世等二十多位英国前国王墓 ...

  2. 【整理】nand相关

    记录nand相关知识.主要是mtd和ubi 什么是UBI 它是一种flash管理方式 flash是一系列连续的物理擦除块组成的. UBI卷是一系列连续的逻辑擦除块(eraseblock),每一块都能够 ...

  3. leetcode题解||Container With Most Water问题

    problem: Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate ...

  4. 死去活来的OC NSArray 中文排序 及输出

    目的 1.NSArray 能够支持中文排序 2.NSLog 能够直接输出 NSArray 内的中文(事实上 java 直接打印数组也不能显示内容哈) 又是死去活来的搞了1个小时,分类实现.废话少说,上 ...

  5. jquery easyui:EasyUI Treegrid 树形网格

    用jquery easyui 的 Treegrid 树形网格 进行数据展示,不过官网的API 和 demo 让我愣了好久,摸索后整理出来供大家详细参看. jquery easyui 官网:http:/ ...

  6. jquery 深入学习笔记之中的一个 (事件绑定)

    [jquery 事件绑定] 1.加入元素事件绑定 (1) 加入事件为当前元素 $('p').on('click',function(){ //code here ... }); (2) 加入事件为未来 ...

  7. LeetCode 112 Path Sum(路径和)(BT、DP)(*)

    翻译 给定一个二叉树root和一个和sum, 决定这个树是否存在一条从根到叶子的路径使得沿路全部节点的和等于给定的sum. 比如: 给定例如以下二叉树和sum=22. 5 / \ 4 8 / / \ ...

  8. BZOJ 1042: [HAOI2008]硬币购物 容斥+背包

    1042: [HAOI2008]硬币购物 Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请 ...

  9. 利用JS判断当前来路域名并跳转到指定页面

    某网站绑定了多个域名,默认情况下访问这些域名的时候是指向网站的首页,也就是访问不同域名时看到的页面是一样的,现在需要访问不同域名时显示不同页面. 一般情况下,可以用子站绑定域名的方法来实现,访问不同的 ...

  10. 织梦CMS如何在首页调用指定的文章 idlist

    在网站首页调用站内新闻是必不可少的,但是有的时候不能根据自己的需要来调用指定的文章,想要调用自己指定的文章还要做一些修改. 在网站中调用指定文章可以使用织梦默认的标签idlist,在调用的时候使用以下 ...