洛谷 P6072 -『MdOI R1』Path(回滚莫队+01-trie)
又是 ix35 神仙出的题,先以 mol 为敬 %%%
首先预处理出根节点到每个点路径上权值的异或和 \(dis_i\),那么两点 \(a,b\) 路径上权值的异或和显然为 \(dis_a\oplus dis_b\)。
我们考虑探究 \(a,b\) 与 \(c,d\) 间的路径不相交意味着什么。记 \(l=lca(a,b)\),显然 \(c,d\) 不能一个在 \(l\) 子树内,一个在 \(l\) 子树外,否则它们间的路径就会经过 \(l\) 了。那么分两种情况,\(c,d\) 全在 \(l\) 子树外,和 \(c,d\) 全在 \(l\) 子树内。\(c,d\) 全在子树外的情况显然好搞定,只要 \(c,d\) 都在 \(l\) 的子树外,那么 \(a,b\) 与 \(c,d\) 之间的路径就肯定不会相交。比较麻烦的是 \(c,d\) 全在 \(l\) 子树内的情况,记 \(l'=lca(c,d)\),显然 \(l'\neq l\),而 \(c,d\) 都在 \(l\) 子树内,故 \(l'\) 也在 \(l\) 子树内,如果我们交换 \((a,b)\) 和 \((c,d)\),那么可得 \(c,d\) 的 lca 在 \(a,b\) 的 lca \(l'\) 的子树外,故第二种情况可以规约到第一种情况。所以我们只用考虑第一种情况就行了。
考虑枚举 \(a,b\) 的 lca \(l\),如果我们按照 DFS 序将原树展开成一个序列,那么相当于在 \([dfn_l,dfn_l+sz_l-1]\) 和 \([1,dfn_l-1]\cup[dfn_l+sz_l,n]\) 中分别选择两个数 \(a,b\) 和 \(c,d\) 使得 \(dis_a\oplus dis_b+dis_c\oplus dis_d\) 最大。那么我们只用让它们分别最大即可。而如果我们令 \(dfn_i=dfn_{i-n}(i>n)\),那么后面那个区间并又可写成 \([dfn_l+sz_l,dfn_l+n-1]\)。于是现在题目转化为:给定一个序列 \(a\),要求在 \([l,r]\) 中选择两个数 \(a_i,a_j\),\(a_i\oplus a_j\) 的最大值。首先可以肯定的是这东西没法用 DS 直接维护,而本题 3e4 的数据范围也在疯狂暗示本题的根号算法。故考虑莫队,建立一个 01-trie,插入某个数 \(x\) 的时候就按照套路将其插入 01-trie,而本题的答案以取 \(\max\) 出现的,不支持删除。故使用回滚莫队,扫到右端点的时候记录一个 \(tmp\) 保存答案,解决一个询问之后就用临时保存的值还原答案即可。
时间复杂度 \(n\sqrt{n}\log w\)
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=3e4;
const int SQRT=245;
const int LOG_N=30;
const int MAXP=1e6;
int n,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],cst[MAXN*2+5],ec=0;
void adde(int u,int v,int w){to[++ec]=v;cst[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
int dis[MAXN+5],dfn[MAXN+5],ed[MAXN+5],id[MAXN+5],tim=0;
void dfs(int x,int f){
dfn[x]=++tim;id[tim]=x;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cst[e];if(y==f) continue;
dis[y]=dis[x]^z;dfs(y,x);
} ed[x]=tim;
}
int blk_sz,blk_cnt,L[SQRT+5],R[SQRT+5],bel[MAXN*2+5];
int w[MAXN*2+5];
struct query{
int l,r,id;
bool operator <(const query &rhs){
if(bel[l]!=bel[rhs.l]) return l<rhs.l;
return r<rhs.r;
}
} q[MAXN*2+5];
int ch[MAXP+5][2],siz[MAXP+5],ncnt=0;
void insert(int x,int v){
int cur=0;
for(int i=LOG_N;~i;i--){
int d=x>>i&1;
if(!ch[cur][d]) ch[cur][d]=++ncnt;
cur=ch[cur][d];siz[cur]+=v;
}
}
int query(int v){
int x=0,cur=0;
for(int i=LOG_N;~i;i--){
int d=v>>i&1;
if(siz[ch[cur][d^1]]) x|=1<<i,cur=ch[cur][d^1];
else cur=ch[cur][d];
} return x;
}
int ans=0,res[MAXN+5];
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
adde(u,v,w);adde(v,u,w);
} dfs(1,0);
for(int i=1;i<=n;i++) w[i]=dis[id[i]];
for(int i=n+1;i<=n*2;i++) w[i]=w[i-n];
// for(int i=1;i<=n*2;i++) printf("%d\n",w[i]);
blk_sz=(int)sqrt(2*n);blk_cnt=(2*n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;
R[i]=min(i*blk_sz,2*n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=2;i<=n;i++){
q[i-1].l=dfn[i];q[i-1].r=ed[i];q[i-1].id=i;
q[i+n-2].l=ed[i]+1;q[i+n-2].r=dfn[i]+n-1;q[i+n-2].id=i;
// printf("%d %d %d\n",dfn[i],ed[i],i);
// printf("%d %d %d\n",ed[i]+1,dfn[i]+n-1,i);
} sort(q+1,q+(n<<1)-1);int cl=1,cr=0;
// for(int i=1;i<=(n<<1)-2;i++) printf("%d %d %d\n",q[i].l,q[i].r,q[i].id);
for(int i=1;i<=(n<<1)-2;i++){
if(i==1||bel[q[i].l]!=bel[q[i-1].l]){
cl=R[bel[q[i].l]]+1;cr=cl-1;
memset(siz,0,sizeof(siz));memset(ch,0,sizeof(ch));
ncnt=0;ans=0;
}
if(bel[q[i].l]==bel[q[i].r]){
int mx=-0x3f3f3f3f;
for(int j=q[i].l;j<=q[i].r;j++) insert(w[j],1);
for(int j=q[i].l;j<=q[i].r;j++) mx=max(mx,query(w[j]));
for(int j=q[i].l;j<=q[i].r;j++) insert(w[j],-1);
res[q[i].id]+=mx;continue;
}
while(cr<q[i].r) insert(w[++cr],1),ans=max(ans,query(w[cr]));
int tmp=ans;
while(cl>q[i].l) insert(w[--cl],1),ans=max(ans,query(w[cl]));
res[q[i].id]+=ans;
while(cl<R[bel[q[i].l]]+1) insert(w[cl++],-1);
ans=tmp;
} int mx=0;
for(int i=1;i<=n;i++) chkmax(mx,res[i]);
printf("%d\n",mx);
return 0;
}
洛谷 P6072 -『MdOI R1』Path(回滚莫队+01-trie)的更多相关文章
- P6072 『MdOI R1』Path
考虑我们有这样操作. 我们只要维护两点在子树内和两点在子树外的异或和即可. 前者可以类似于线段树合并的trie树合并. 后者有两种做法: 一种是把dfn序翻倍:然后子树补变成了一个区间最大异或问题,可 ...
- 洛谷 P6071 『MdOI R1』Treequery(LCA+线段树+主席树)
题目链接 题意:给出一棵树,有边权,\(m\) 次询问,每次给出三个数 \(p,l,r\),求边集 \(\bigcap\limits_{i=l}^rE(p,i)\) 中所有边的权值和. 其中 \(E( ...
- 洛谷 P6383 -『MdOI R2』Resurrection(DP)
洛谷题面传送门 高速公路上正是补 blog 的时候,难道不是吗/doge,难不成逆在高速公路上写题/jy 首先形成的图显然是连通图并且有 \(n-1\) 条边.故形成的图是一棵树. 我们考虑什么样的树 ...
- 【洛谷3674】小清新人渣的本愿(莫队,bitset)
[洛谷3674]小清新人渣的本愿(莫队,bitset) 题面 洛谷,自己去看去,太长了 题解 很显然的莫队. 但是怎么查询那几个询问. 对于询问乘积,显然可以暴力枚举因数(反正加起来也是\(O(n\s ...
- 【洛谷5398】[Ynoi2018]GOSICK(二次离线莫队)
题目: 洛谷 5398 当我刚学莫队的时候,他们告诉我莫队能解决几乎所有区间问题: 现在,当我发现一个区间问题似乎难以用我所了解的莫队解决的时候,他们就把这题的正解叫做 XXX 莫队.--题记 (以上 ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]
传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...
- 洛谷 P1494 [国家集训队]小Z的袜子(莫队)
题目链接:https://www.luogu.com.cn/problem/P1494 一道很经典的莫队模板题,然而每道莫队题的大体轮廓都差不多. 首先莫队是一种基于分块的算法,它的显著特点就是: 能 ...
- 『MdOI R1』Treequery
我们可以思考怎么做呢. 首先我们需要进行一些分类讨论: 我们先思考一下如果所有关键点都在 \(p\) 的子树内, 那显然是所有关键点的 \(Lca\) 到 \(p\) 距离. 如果所有关键点一些在 \ ...
- 【洛谷】1972:[SDOI2009]HH的项链【莫队+树状数组】
P1972 [SDOI2009]HH的项链 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含 ...
随机推荐
- 免费 CDN 玩法 —— 文件一键上传到 NPM
前言 unpkg.jsdelivr 等站点可加速 NPM 包文件,适合作为个人网站或演示案例的免费 CDN. 虽然上传文件到 NPM 很简单,创建 package.json 然后 npm publis ...
- 原生js-返回顶部
html部分: <body style="height:2000px"> <div id="div1"> 返回顶部 </div&g ...
- F1英国大奖赛-银石赛道地图及弯道
背景 今天晚上(2020-08-02)是今年英国大奖赛的正赛.刚好了解了一下赛道地图.记录一下,明年就不用到处找了. 简介 银石赛道(Silverstone Circuit)由一个废弃的空军基地改建, ...
- SLAM名词介绍
gauge freedom:测量自由度 degrees-of-freedom(DoF) 自由度 wide-baseline matches:宽基线匹配 宽基线匹配:从描绘同一场景的两个或多个图像中建立 ...
- Python小练习之验证“哥德巴赫猜想”
设计内容:任何一个大于2的偶数都可以分解为两个素数之和,这就是著名的哥达巴赫猜想. 设计要求:要求输入一个大于2的偶数,程序运行后,输出两个素数,其和正好等于该偶数. 1. 实验代码(知道是你们 ...
- 组件通过props属性传值
组件之间的传值 组件是一个单独功能模块的封装,有属于自己的data和methods,一个组件的 data 选项必须是一个函数 为什么必须是函数:因为只有当data是函数时,不同实例调用同一个组件时才会 ...
- webpack 提取css成单独文件
webpack 提取css成单独文件 // 用来拼接绝对路径的方法 const {resolve} = require('path') const HtmlWebpackPlugin = requir ...
- sqlalchemy flush commit
https://segmentfault.com/q/1010000000698181 flush 将sql发送到内存 commit 真正提交
- Java 中的关键字
Java 中有多少个关键字,有大小写之分吗? Java 中有 48 个关键字在使用 + 两个保留关键字未使用,共 50 个关键字. Java 关键字全部都由是小写组成. Java 中保留关键字分别是哪 ...
- Django笔记&教程 6-1 表单(Form)介绍
Django 自学笔记兼学习教程第6章第1节--表单(Form)介绍 点击查看教程总目录 1 介绍 如果网站要让用户输入并提交数据(比如注册登录),则需要用到表单. 单纯的html也能写出表单,格式一 ...