传送门

题意

分析

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. Android安全机制介绍

    Android的安全机制包含下面几个方面:      • 进程沙箱隔离机制.      • 应用程序签名机制.      • 权限声明机制.      • 訪问控制机制.      • 进程通信机制. ...

  2. C++中的数组array和vector,lambda表达式,C字符串加操作,C++中新类型数组(数组缓存),多元数组,new缓冲

     使用C++风格的数组.不须要管理内存. array要注意不要溢出,由于它是栈上开辟内存. array适用于不论什么类型 #include<iostream> #include< ...

  3. Qt:解析命令行

    Qt从5.2版開始提供了两个类QCommandLineOption和QCommandLineParser来解析应用的命令行參数. 一.命令行写法 命令行:"-abc" 在QComm ...

  4. ios系统铃声调用方法

    首先,这里我要说明这里并非真正调用系统内部自带的铃声,由于苹果是不同意开发人员调用的,没有给开发人员接口.假设调用了就无法上线的! 那为什么AppStore里面还有那么多app显示的效果是调用系统的铃 ...

  5. 通视频URL截取第一帧图片

    为了方便直接给UIImage加个类别,以后什么时候使用可以直接调用. #import <UIKit/UIKit.h> @interface UIImage (Video) /** 通过视频 ...

  6. mac classpath设置

    I've been searching for the answer daylong, and finally had the problems solved. I am going to write ...

  7. Android的onMeasure方法

    在Android开发中,当Android原生控件不能满足我们的需求的时候,就需要自定义View.View在屏幕上绘制出来先要经过measure(计算)和layout(布局). 什么时候调用onMeas ...

  8. wxpython中控件对键盘输入无响应的可能原因

    问题描述: 开发环境:Win7 32bit + Python2.7.6 + WxPython 3.0.1-b20140707 开发某初级CAD软件中,需要实现点击TreeCtrl控件的相应选择,实现G ...

  9. debian apt-get工作的原理

    1 apt-get update apt-get update并没有将远程仓库的包都下载到本地,而是通过访问远程仓库创建或者更新了远程仓库的本地索引,索引文件放在/var/lib/apt/lists目 ...

  10. 浅谈HTTPS连接

    相信很多朋友都遇到过网页被强插广告的情况,好端端一个干净的页面,动不动就被插了个屠龙宝刀点击就送的小窗口,看着就心烦.这种网页劫持强插广告的现象,在中国非常常见,往往是运营商进行HTTP劫持所造成的. ...