Query on a tree IV SPOJ - QTREE4
https://vjudge.net/problem/SPOJ-QTREE4
点分就没有一道不卡常的?

卡常记录:
1.把multiset换成手写的带删除堆(套用pq)(作用很大)
2.把带删除堆里面pq换成用vector+push_heap/pop_heap(作用较小)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
struct E
{
int to,nxt,d;
}e[];
int f1[],ne;
int ff[],n,sum,fx[],sz[];
int eu[],pos[],dpx[],dpx2[],st[][],log2x[],lft[];
int root;
bool fl[],vis[];
struct xxx
{
priority_queue<int> q1,q2;int sz;
void insert(int x){q1.push(x);++sz;}
void erase(int x){q2.push(x);--sz;}
int size() {return sz;}
void cl()
{
while(!q1.empty()&&!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
}
void pop()
{
cl();q1.pop();--sz;
}
int top()
{
cl();return q1.top();
}
bool empty() {return sz==;}
};
xxx s[],s2[],s3;
//s[i]:i点管辖的连通块各个点到i点上层重心的距离
//s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离)
//s3:各个s2的前2大值之和
int getdis(int x,int y)
{
int l=pos[x],r=pos[y];if(l>r) swap(l,r);
int k=log2x[r-l+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+][k]]]?st[r-lft[k]+][k]:st[l][k];
return dpx2[pos[x]]+dpx2[pos[y]]-*dpx2[pos[t]];
}
void getroot(int u,int fa)
{
sz[u]=;fx[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getroot(e[k].to,u);
sz[u]+=sz[e[k].to];
fx[u]=max(fx[u],sz[e[k].to]);
}
fx[u]=max(fx[u],sum-sz[u]);
if(fx[u]<fx[root]) root=u;
}
void getsz(int u,int fa)
{
sz[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getsz(e[k].to,u);
sz[u]+=sz[e[k].to];
}
}
void getdeep(int u,int fa)
{
s[root].insert(getdis(u,ff[root]));
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
getdeep(e[k].to,u);
}
char tmp[];
int getmax2(int p)
{
if(s2[p].size()<) return -0x3f3f3f3f;
int t1=s2[p].top();s2[p].pop();int t2=s2[p].top();s2[p].insert(t1);
return t1+t2;
}
void solve(int u)
{
vis[u]=;
s2[u].insert();
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to])
{
getsz(e[k].to,);sum=sz[e[k].to];
root=;getroot(e[k].to,);
ff[root]=u;getdeep(root,);
if(!s[root].empty()) s2[u].insert(s[root].top());
solve(root);
}
s3.insert(getmax2(u));
}
void dfs1(int u,int fa,int d,int d2)
{
eu[++eu[]]=u;pos[u]=eu[];dpx[eu[]]=d;dpx2[eu[]]=d2;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs1(e[k].to,u,d+,d2+e[k].d);
eu[++eu[]]=u;
dpx[eu[]]=d;
dpx2[eu[]]=d2;
}
}
//void debugxxxx(multiset<int>& s)
//{
// for(auto i : s) printf("%d ",i);
// puts("test");
//}
void change(int u)
{
int now;
s3.erase(getmax2(u));
if(!fl[u]) s2[u].erase();
for(now=u;ff[now];now=ff[now])
{
s3.erase(getmax2(ff[now]));
if(!s[now].empty()) s2[ff[now]].erase(s[now].top());
if(!fl[u]) s[now].erase(getdis(u,ff[now]));
}
fl[u]^=;
if(!fl[u]) s2[u].insert();
s3.insert(getmax2(u));
for(now=u;ff[now];now=ff[now])
{
if(!fl[u]) s[now].insert(getdis(u,ff[now]));
if(!s[now].empty()) s2[ff[now]].insert(s[now].top());
s3.insert(getmax2(ff[now]));
}
}
int num;
int main()
{
lft[]=;
fx[]=0x3f3f3f3f;
int i,j,a,b,la=,q,t,c;
for(i=;i<=;i++) lft[i]=(lft[i-]<<);
for(i=;i<=;i++)
{
if(i>=lft[la+]) ++la;
log2x[i]=la;
}
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
e[++ne].to=b;e[ne].nxt=f1[a];e[ne].d=c;f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];e[ne].d=c;f1[b]=ne;
}
dfs1(,,,);
for(i=;i<=eu[];i++) st[i][]=eu[i];
for(j=;(<<j)<=eu[];j++)
for(i=;i+lft[j]-<=eu[];i++)
if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+lft[j-]][j-]]])
st[i][j]=st[i+lft[j-]][j-];
else
st[i][j]=st[i][j-];
sum=n;getroot(,);
solve(root);
scanf("%d",&q);
num=n;
while(q--)
{
scanf("%s",tmp);
if(tmp[]=='A')
{
if(num==) printf("They have disappeared.\n");
else if(num==) printf("0\n");
else printf("%d\n",max(s3.top(),));
}
else if(tmp[]=='C')
{
scanf("%d",&t);
if(fl[t]) num++;else num--;
change(t);
}
}
return ;
}
upd20181231:
用网上的链分治做法重写了,果然常数小很多,可以A了,然而代码量似乎更大
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
struct E
{
int to,nxt,d;
}e[];
int f1[],ne;
const int inf1=0x3f3f3f3f;
struct Set
{
priority_queue<int> s,t;int sz;
void push(int x){s.push(x);++sz;}
void erase(int x){t.push(x);--sz;}
int top()
{
while(s.size()&&t.size()&&s.top()==t.top())
s.pop(),t.pop();
return sz?s.top():-inf1;
}
int sum2()//最大2个之和
{
if(sz<) return ;
int a1=top();erase(a1);
int a2=top();push(a1);
return a1+a2;
}
}q[],&q0=q[];
int d[];
struct I
{
int da,db,d;
//a表示向下最长轻链,d表示到1距离;max{a+d},max{a-d},max{ar+al+dr-dl}
};
void merge(I &c,const I &a,const I &b)
{
c.da=max(a.da,b.da);
c.db=max(a.db,b.db);
c.d=max(max(a.d,b.d),b.da+a.db);
}
namespace S
{
struct D
{
int lc,rc;I d;
}g[];
int mem;
#define LC g[u].lc
#define RC g[u].rc
void upd(int u){merge(g[u].d,g[LC].d,g[RC].d);}
I x;int L;
/*
void init()
{
g[0].d.da=g[0].d.db=g[0].d.d=-inf1;
}
inline int gnode()
{
int t=++mem;
g[t].d.da=g[t].d.db=g[t].d.d=g[t].d.a=-inf1;
return t;
}
*/
void _setx(int l,int r,int &u)
{
if(!u) u=++mem;
if(l==r)
{
g[u].d=x;
return;
}
int mid=(l+r)>>;
if(L<=mid) _setx(l,mid,LC);
else _setx(mid+,r,RC);
upd(u);
}
I getx(int L,int R,int l,int r,int u)
{
if(L<=l&&r<=R) return g[u].d;
int mid=(l+r)>>;
if(L<=mid&&mid<R)
{
I t;merge(t,getx(L,R,l,mid,LC),getx(L,R,mid+,r,RC));
return t;
}
else if(L<=mid)
return getx(L,R,l,mid,LC);
else if(mid<R)
return getx(L,R,mid+,r,RC);
}
}
int dep[],sz[];
int d2[],hson[];
int ff[];
void dfs1(int u,int fa)
{
sz[u]=;
int v;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
v=e[k].to;
ff[v]=u;
dep[v]=dep[u]+;
d[v]=d[u]+e[k].d;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[hson[u]]) hson[u]=v;
}
}
int b[],pl[],tp[],dwn[],len[];
int rt[],oknum;
bool ok[];
int n,m;
void dfs2(int u,int fa)
{
ok[u]=;q[u].push();
b[++b[]]=u;pl[u]=b[];
tp[u]=(u==hson[fa])?tp[fa]:u;
if(hson[u]) dfs2(hson[u],u);
dwn[u]=hson[u]?dwn[hson[u]]:u;
len[u]=dep[dwn[u]]-dep[tp[u]]+;
int v,k;
for(k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa&&e[k].to!=hson[u])
{
v=e[k].to;
dfs2(v,u);
q[u].push(d2[v]-d[u]);
}
{
int t=q[u].top();
using namespace S;
x.da=t+d[u];x.db=t-d[u];x.d=q[u].sum2();
L=dep[u]-dep[tp[u]]+;_setx(,len[u],rt[tp[u]]);
}
if(u==tp[u])
{
const I &t=S::g[rt[u]].d;
d2[u]=t.da;
q0.push(t.d);
}
}
int main()
{
int i,x,y,z,t,u,v;
char tmp[];
//S::init();
scanf("%d",&n);
for(i=;i<n;++i)
{
scanf("%d%d%d",&x,&y,&z);
e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;
e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;e[ne].d=z;
}
dfs1(,);
oknum=n;
dfs2(,);
//printf("%d\n",q0.top());
scanf("%d",&m);
while(m--)
{
scanf("%s",tmp);
if(tmp[]=='C')
{
scanf("%d",&u);
if(ok[u])
{
--oknum;
q[u].erase();
}
else
{
++oknum;
q[u].push();
}
ok[u]^=;
while(u)
{
q0.erase(S::g[rt[tp[u]]].d.d);
{
t=q[u].top();
using namespace S;I &x=S::x;
x.da=t+d[u];x.db=t-d[u];x.d=q[u].sum2();
L=dep[u]-dep[tp[u]]+;_setx(,len[u],rt[tp[u]]);
}
u=tp[u];v=ff[u];
const I &t=S::g[rt[u]].d;
if(v) q[v].erase(d2[u]-d[v]);
d2[u]=t.da;
if(v) q[v].push(d2[u]-d[v]);
q0.push(t.d);
u=v;
}
}
else
{
if(!oknum)
{
puts("They have disappeared.");
continue;
}
printf("%d\n",q0.top());
}
}
return ;
}
Query on a tree IV SPOJ - QTREE4的更多相关文章
- SPOJ QTREE4 SPOJ Query on a tree IV
You are given a tree (an acyclic undirected connected graph) with N nodes, and nodes numbered 1,2,3. ...
- SPOJ QTREE4 - Query on a tree IV
You are given a tree (an acyclic undirected connected graph) with N nodes, and nodes numbered 1,2,3. ...
- SPOJ QTREE4 - Query on a tree IV 树分治
题意: 给出一棵边带权的树,初始树上所有节点都是白色. 有两种操作: C x,改变节点x的颜色,即白变黑,黑变白 A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为0). 分析: ...
- SPOJ QTREE4 Query on a tree IV ——动态点分治
[题目分析] 同bzoj1095 然后WA掉了. 发现有负权边,只好把rmq的方式改掉. 然后T了. 需要进行底(ka)层(chang)优(shu)化. 然后还是T 下午又交就A了. [代码] #in ...
- SPOJ - QTREE4 Query on a tree IV 边分治
题目传送门 题意:有一棵数,每个节点有颜色,黑色或者白色,树边有边权,现在有2个操作,1修改某个点的颜色, 2询问2个白点的之前的路径权值最大和是多少. 题解: 边分治思路. 1.重构图. 因为边分治 ...
- 【SPOJ QTREE4】Query on a tree IV(树链剖分)
Description 给出一棵边带权(\(c\))的节点数量为 \(n\) 的树,初始树上所有节点都是白色.有两种操作: C x,改变节点 \(x\) 的颜色,即白变黑,黑变白. A,询问树中最远的 ...
- 2019.02.16 spoj Query on a tree IV(链分治)
传送门 题意简述: 捉迷藏强化版(带有边权,可以为负数) 思路:好吧这次我们不用点分树,我们用听起来更屌的链分治. 直接把树剖成若干条重链,这样保证从任意一个点跳到根节点是不会跳超过logloglog ...
- 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...
- SP2666 QTREE4 - Query on a tree IV(LCT)
题意翻译 你被给定一棵n个点的带边权的树(边权可以为负),点从1到n编号.每个点可能有两种颜色:黑或白.我们定义dist(a,b)为点a至点b路径上的权值之和. 一开始所有的点都是白色的. 要求作以下 ...
随机推荐
- ViewFlow增强onItemClick功能及ViewFlow AbsListView源代码分析
先看实现效果,上图: ViewFlow是一个非常好用的,用于不确定item个数的水平滑动切换的开源项目. 可是从github上下载的ViewFlow事实上是不支持onItemClick功能的,tou ...
- 模板方法模式-TemplateMethod
模板方法模式:定义一个操作中的算法骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的机构即可以重定义算法的某些特定步骤. 模板方法模式是通过吧不变形为搬移到超类,去除子类中的重复代码 ...
- 常用到的JS 验证(包括例子)
//验证是否为空 function check_blank(obj, obj_name){ if(obj.value != ''){ retur ...
- 前端遇上Go: 静态资源增量更新的新实践
前端遇上Go: 静态资源增量更新的新实践https://mp.weixin.qq.com/s/hCqQW1F8FngPPGZAisAWUg 前端遇上Go: 静态资源增量更新的新实践 原创: 洋河 美团 ...
- mvn 引入自定义jar 解决 mongo-spark 报错
[root@hadoop1 bin]# ./spark-submit ---bin-hadoop2./mycode/myprojectname/target/myprojectname-1.0-SNA ...
- iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用
目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 多线程的四种解决方案:pthread,NSThread,GCD,N ...
- hdu 5615 Jam's math problem(十字相乘判定)
d. Jam有道数学题想向你请教一下,他刚刚学会因式分解比如说,x^2+6x+5=(x+1)(x+5) 就好像形如 ax^2+bx+c => pqx^2+(qk+mp)x+km=(px+k)(q ...
- [Selenium] 使用Chrome Driver 的示例
//导入Selenium 库和 ChromeDriver 库 pachage com.learningselenium.simplewebdriver; import java.util.concur ...
- 【SDOI2012】 Longgue的问题
[题目链接] 点击打开链接 [算法] gcd(i,n)是n的约数 不妨设gcd(i,n) = d 考虑枚举d和gcd(i,n) = d有多少个 gcd(i,n) = d gcd(i/d,n/d) = ...
- bzoj1003物流运输——DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1003 DP好题: 直接找一个时间段的最短路,并用它来预处理出每个时间段的最小花费: f[i] ...