HDU5589 Tree【分块 01字典树】
2024-10-19 05:02:20
HDU5589 Tree
题意:
给出一棵\(N\)个点的树,每条边有边权,每次询问下标为\([L,R]\)区间内的点能选出多少点对,点对之间的路径上的边权异或和大于\(M\)
题解:
对于两点\(u,v\)之间的路径上的边权的异或和,可以转化为根到点\(u\)的路径上异或和与根到点\(v\)的路径上异或和的异或和,所以可以与处理出根到各个点的路径边权异或和
接下来就变成了一个序列上的问题了,每次询问区间\([L,R]\)之间的点有多少对的异或和大于\(M\)
然后就可以用莫队来处理,为了能快速加值和删值还有查询,而且是异或的操作,这里选择用\(01\)字典树来做
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 5e4+7;
typedef long long int LL;
int n,m,q,w[MAXN];
LL ret[MAXN],ans;
struct Trie{
int tot,ch[MAXN<<4][2],cnt[MAXN<<4];
void clear(){
for(int i = 1; i <= tot; i++) ch[i][0] = ch[i][1] = cnt[i] = 0;
tot = 1;
}
void insert(int x, int now = 1){
for(int i = 19; i >= 0; i--){
if(!ch[now][(x>>i)&1]) ch[now][(x>>i)&1] = ++tot;
cnt[now = ch[now][(x>>i)&1]]++;
}
}
void erase(int x, int now = 1){
for(int i = 19; i >= 0; i--) cnt[now = ch[now][(x>>i)&1]]--;
}
int query(int x){
int ret = 0, now = 1;
for(int i = 19; i >= 0 and now; i--){
int bm = ((m>>i)&1);
int bx = ((x>>i)&1);
if(!bm) ret += cnt[ch[now][bx^1]], now = ch[now][bx];
else now = ch[now][bx^1];
}
return ret;
}
}trie;
struct Query{ int l, r, id; } Q[MAXN];
vector<pair<int,int>> G[MAXN];
void dfs(int u, int par){
for(auto e : G[u]) if(e.first!=par){
w[e.first] = w[u] ^ e.second;
dfs(e.first,u);
}
}
void inc(int x){
ans += trie.query(x);
trie.insert(x);
}
void dec(int x){
trie.erase(x);
ans -= trie.query(x);
}
void solve(){
for(int i = 1; i <= n; i++) G[i].clear();
for(int i = 1; i < n; i++){
int u, v, wt;
scanf("%d %d %d",&u,&v,&wt);
G[u].push_back(make_pair(v,wt)); G[v].push_back(make_pair(u,wt));
}
dfs(1,0); trie.clear();
for(int i = 1; i <= q; i++) scanf("%d %d",&Q[i].l,&Q[i].r), Q[i].id = i;
int sqt = sqrt(n);
sort(Q+1,Q+1+q,[&sqt](const Query &lhs, const Query &rhs){
return lhs.l / sqt == rhs.l / sqt ? lhs.r < rhs.r : lhs.l / sqt < rhs.l / sqt;
});
int L = 1, R = 0;
ans = 0;
for(int i = 1; i <= q; i++){
while(L>Q[i].l) inc(w[--L]);
while(R<Q[i].r) inc(w[++R]);
while(L<Q[i].l) dec(w[L++]);
while(R>Q[i].r) dec(w[R--]);
ret[Q[i].id] = ans;
}
for(int i = 1; i <= q; i++) printf("%I64d\n",ret[i]);
}
int main(){
while(scanf("%d %d %d",&n,&m,&q)!=EOF) solve();
return 0;
}
最新文章
- SOA服务类项目开发模式
- 数据挖掘算法(一)C4.5
- javaweb学习总结(二十九)——EL表达式
- Android NDK 构建 以及一些错误
- DiskGenius的 “终止位置参数溢出”错误解决方法。
- Java中的事务——JDBC事务和JTA事务
- android的版本控制
- POJ 2396 Budget 有上下界的网络流
- Swift中实现ruby中字符串乘法倍增的功能
- 手动清除mac的广告弹框病毒 MacOSDefender
- Google Apps的单点登录-谷歌使用的单点登录
- 【FFmpeg】ffplay播放rtsp视频流花屏问题 (转)
- 在dbgrideh中允许选择多行,如何知道哪些行被选中
- python: numpy--函数 shape用法
- php让页面记住表单提交后的信息方法
- codeforces9D How many trees?
- HDU 2143 Can you find it?(基础二分)
- android gallery 自定义边框+幻灯片效果
- hdoj 1026 Ignatius and the Princess I 最小步数,并且保存路径
- Zabbix分布式监控
热门文章
- js如何替换字符串中匹配到多处中某一指定节点?
- Linux SSH , SCP 建立信任关系(免密传输)
- 基于Docker搭建Hadoop+Hive
- Java高并发与多线程(二)-----线程的实现方式
- SpringBoot快速掌握(1):核心技术
- Navicat linux 官方最新版安装破解
- OLED的波形曲线、进度条、图片显示(STM32 HAL库 模拟SPI通信 5线OLED屏幕)详细篇
- Docker容器日志清理方案
- 理想的DevOp流程怎么做?看看Slack的代码部署实践 原创 Michael Deng 高可用架构 今天
- (Sql Server)Soundex语音算法