Qtree1,2,3暂缺
Qtree4思路
总是有机房大佬问我怎么做(抄题解不就好了吗?),那我就讲一讲我紊乱的思路吧。
应该不难想到边权下放到子节点,有了这个基础,我们对细节的处理就不用那么模糊了。
先上定义:
l s ls ls为当前辅助树以中序遍历形成的链(在原树上也是一条链),严格以链的开头为起点,往深度递增方向拓展,找到白节点则返回值,找不到返回负无穷。
r s rs rs为当前链的结尾,往深度递减方向拓展。
m s ms ms为当前这层的最优解。
由于 S p l a y Splay Splay是二叉的,但是原树是多叉的,那么当前状态会有多个儿子,但只有一个是实儿子(即在 S p l a y Splay Splay中的右儿子),那么我们要多开一个平衡树,来维护虚儿子对答案有贡献的状态。
这时 S T L 大 法 好 STL大法好 STL大法好
开一个
s
e
t
set
set,(秒天秒地秒空气),强行维护一下虚儿子的
l
s
ls
ls。返回一个虚儿子最大的
l
s
ls
ls,称之为
h
f
l
s
hfls
hfls,返回一个虚儿子次大的
l
s
ls
ls,称之为
h
s
l
s
hsls
hsls.(以后有用,如果有问题去问致远星),返回虚儿子最大的
m
s
ms
ms,称之为
c
f
m
s
cfms
cfms。
w = 0 w=0 w=0代表白色。
不严谨的状态转移
这难道不是一个DP吗???!(设 p p p为当前状态, l c = t [ p ] . s o n [ 0 ] lc=t[p].son[0] lc=t[p].son[0]即为p在原链上的祖宗(至少是父亲),辅助树的左儿子, r c = t [ p ] . s o n [ 1 ] rc=t[p].son[1] rc=t[p].son[1])
t [ p ] . l s = m a x { t [ l c ] . l s , t [ l c ] . s + t [ p ] . d + t [ r c ] . l s , t [ l c ] . s + t [ p ] . d + t [ p ] . h f l s , t [ l c ] . s + t [ p ] . d } t[p].ls=max\begin{Bmatrix}t[lc].ls,t[lc].s+t[p].d+t[rc].ls,t[lc].s+t[p].d+t[p].hfls,t[lc].s+t[p].d\end{Bmatrix} t[p].ls=max{t[lc].ls,t[lc].s+t[p].d+t[rc].ls,t[lc].s+t[p].d+t[p].hfls,t[lc].s+t[p].d}
t [ p ] . r s = m a x { t [ r c ] . r s , t [ r c ] . s + t [ p ] . d + t [ l c ] . r s , t [ r c ] . s + t [ p ] . h f l s } t[p].rs=max\begin{Bmatrix}t[rc].rs,t[rc].s+t[p].d+t[lc].rs,t[rc].s+t[p].hfls\end{Bmatrix} t[p].rs=max{t[rc].rs,t[rc].s+t[p].d+t[lc].rs,t[rc].s+t[p].hfls}
但是,有可能没有白节点,这时就需要返回负无穷。
为了方便计算, t [ p ] . w t[p].w t[p].w可以表示一个实值,也可以表示为颜色;
当 t [ p ] . w = 0 t[p].w=0 t[p].w=0时,为白色,否则, t [ p ] . w t[p].w t[p].w为负无穷
令 w = m a x ( t [ p ] . w , t [ p ] . h f l s ) , L = m a x ( w , t [ l c ] . r s + t [ p ] . d ) , R = m a x ( w , t [ r c ] . l s ) w=max(t[p].w,t[p].hfls),L=max(w,t[lc].rs+t[p].d),R=max(w,t[rc].ls) w=max(t[p].w,t[p].hfls),L=max(w,t[lc].rs+t[p].d),R=max(w,t[rc].ls)
辣么,
t [ p ] . l s = m a x { t [ l c ] . l s , t [ l c ] . s + t [ p ] . d + R } t[p].ls=max\begin{Bmatrix}t[lc].ls,t[lc].s+t[p].d+R\end{Bmatrix} t[p].ls=max{t[lc].ls,t[lc].s+t[p].d+R}
t [ p ] . r s = m a x { t [ r c ] . r s , t [ r c ] . s + L } t[p].rs=max\begin{Bmatrix}t[rc].rs,t[rc].s+L\end{Bmatrix} t[p].rs=max{t[rc].rs,t[rc].s+L}
t [ p ] . m s = m a x { t [ l c ] . m s , t [ r c ] . m s , t [ l c ] . r s + t [ p ] . d + R , L + t [ r c ] . l s , t [ p ] . h f l s , t [ p ] . h f l s + t [ p ] . h s l s , t [ p ] . c f m s , i f ( t [ p ] . w = = 0 ) 0 , t [ p ] . h f l s } t[p].ms=max\begin{Bmatrix}t[lc].ms,t[rc].ms,t[lc].rs+t[p].d+R,L+t[rc].ls,t[p].hfls,\\t[p].hfls+t[p].hsls,t[p].cfms,if(t[p].w==0)0,t[p].hfls\end{Bmatrix} t[p].ms=max{t[lc].ms,t[rc].ms,t[lc].rs+t[p].d+R,L+t[rc].ls,t[p].hfls,t[p].hfls+t[p].hsls,t[p].cfms,if(t[p].w==0)0,t[p].hfls}
状态很多,细细理解。
另外在 a c c e s s access access时,要改变 t [ x ] . s o n [ 1 ] t[x].son[1] t[x].son[1],这时要注意改变实虚儿子。
贴上一份代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define gc getchar()
using namespace std;
const int N=1e5+10;
const int inf=1<<28;
inline void qr(int &x)
{
x=0;char c=gc;int f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
multiset<int>h[N],c[N];
int fir(multiset<int>&s){return s.size()?*s.rbegin():-inf;}
int sec(multiset<int>&s){return s.size()>1?*(++s.rbegin()):-inf;}
struct node{int ls,ms,rs,hfls,hsls,cfms,s,d,son[2],f,w;}t[N];int ans;
inline bool nroot(int p){return t[t[p].f].son[0]==p||t[t[p].f].son[1]==p;}
void update_set(int p){t[p].hfls=fir(h[p]),t[p].hsls=sec(h[p]),t[p].cfms=fir(c[p]);}
inline void update(int x)
{
int lc=t[x].son[0],rc=t[x].son[1];
t[x].s=t[lc].s+t[rc].s+t[x].d;
int w=max(t[x].w,t[x].hfls);/*如果变白了,t[x].w=0,否则为-inf,这样方便计算*/
int L=max(w,t[lc].rs+t[x].d);/*L为x的左子树(实际为x的一系列祖宗)。自己理解就好了*/
int R=max(w,t[rc].ls);/*类似于L,不含x点权*/
t[x].ls=max(t[lc].ls,t[lc].s+t[x].d+R);/*如果要包含左子树,那么一定要包括x*/
t[x].rs=max(t[rc].rs,t[rc].s+L);
/*ms需要继承的状态很多,有当前链的最长距离,左子树右子树的ms,之前统计过的ls的最大值与次大值之和,也就是hfls+hsls*/
/*之前的最大ms,也就是pfms,如果当前点x为白色,那么也可以考虑hfls,再不济也为0*/
t[x].ms=max(t[lc].rs+t[x].d+R,t[rc].ls+L);
t[x].ms=max(max(t[lc].ms,t[rc].ms),t[x].ms);
t[x].ms=max(t[x].ms,t[x].hfls+t[x].hsls);
t[x].ms=max(t[x].ms,t[x].cfms);
if(!t[x].w)t[x].ms=max(max(t[x].ms,t[x].hfls),0);
}
void rotate(int p,int w)
{
int f=t[p].f,gf=t[f].f;
int r=t[p].son[w],R=f;t[R].son[w^1]=r;if(r)t[r].f=R;
r=p;R=gf;if(nroot(f))t[R].son[t[R].son[1]==f]=r;t[r].f=R;
r=f;R=p;t[R].son[w]=r;t[r].f=R;update(f);update(p);
}
void splay(int p)
{
while(nroot(p))
{
int f=t[p].f,gf=t[f].f;
if(!nroot(f))rotate(p,t[f].son[0]==p);
else
{
if(t[f].son[0]==p&&t[gf].son[0]==f)rotate(f,1),rotate(p,1);
else if(t[f].son[0]==p&&t[gf].son[1]==f)rotate(p,1),rotate(p,0);
else if(t[f].son[1]==p&&t[gf].son[0]==f)rotate(p,0),rotate(p,1);
else rotate(f,0),rotate(p,0);
}
}
}
void access(int x)
{
for(int y=0;x;x=t[y=x].f)
{
splay(x);if(t[x].son[1])h[x].insert(t[t[x].son[1]].ls),c[x].insert(t[t[x].son[1]].ms);
if(y)h[x].erase(h[x].find(t[y].ls)),c[x].erase(c[x].find(t[y].ms));
update_set(x);t[x].son[1]=y;update(x);
}
}
void change(int x)
{
access(x);splay(x);
t[x].w?t[x].w=0:t[x].w=-inf;
update(x);ans=t[x].ms;
}
struct edge{int x,y,d,next;}a[N<<1];int last[N],len;
inline void ins(int x,int y,int d){a[++len]=(edge){x,y,d,last[x]};last[x]=len;}
void maketree(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y==t[x].f)continue;
t[y].f=x;t[y].d=a[k].d;maketree(y);
h[x].insert(t[y].ls);c[x].insert(t[y].ms);
}
update_set(x);update(x);
}
int main()
{
int n;qr(n);
for(int i=0;i<=n;i++)t[i].ls=t[i].rs=t[i].ms=-inf;
for(int i=1;i<n;i++){int x,y,d;qr(x),qr(y),qr(d);ins(x,y,d);ins(y,x,d);}
maketree(1);ans=t[1].ms;
int T;qr(T);
while(T--)
{
char s[10];int x;scanf("%s",s+1);
if(s[1]=='A')ans<0?puts("They have disappeared."):printf("%d\n",ans);
else qr(x),change(x);
}
return 0;
}
Qtree5思路
emmm,貌似是一道弱化版的题目,连 m s ms ms都不用,辣么,
l s ls ls, r s rs rs不变。
仔细观察 r s rs rs定义,一定从链的结尾出发,找最近的白点距离。
忽然顿悟(看题解!),先打通x到根的路径( a c c e s s s ( x ) accesss(x) accesss(x)),再把x旋上辅助树的根节点,辣么,现在 x x x只有左儿子咯(因为x是深度最大的点啊),恰好,就可以发现 t [ x ] . r s t[x].rs t[x].rs就是从 x x x出发,去找最近的白点。
之后就是维护一下状态的事情了。
定义 w = m i n ( t [ p ] . w , t [ p ] . h f l s ) , L = m i n ( w , t [ l c ] . r s + t [ p ] . d ) , R = m i n ( w . , t [ r c ] . l s ) ; w=min(t[p].w,t[p].hfls),L=min(w,t[lc].rs+t[p].d),R=min(w.,t[rc].ls); w=min(t[p].w,t[p].hfls),L=min(w,t[lc].rs+t[p].d),R=min(w.,t[rc].ls);
则有 t p ] . l s = m i n { t [ l c ] . l s , t [ l c ] . s + t [ p ] . d + R } tp].ls=min\begin{Bmatrix}t[lc].ls,t[lc].s+t[p].d+R\end{Bmatrix} tp].ls=min{t[lc].ls,t[lc].s+t[p].d+R}
t [ p ] . r s = m i n { t [ r c ] . r s , t [ r c ] . s + L } t[p].rs=min\begin{Bmatrix}t[rc].rs,t[rc].s+L\end{Bmatrix} t[p].rs=min{t[rc].rs,t[rc].s+L}
状态定义参照 Q t r e e 4 Qtree4 Qtree4
照例贴上一份代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<set>
#define gc getchar()
using namespace std;
const int N=1e5+10;
const int inf=1<<28;
inline void qr(int &x)
{
x=0;char c=gc;int f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
multiset<int>h[N];
int fir(multiset<int>&s){return s.size()?*s.begin():inf;}
struct node{int f,son[2],s,ls,rs,hfls,w;}t[N];//hfls是x的所有虚儿子的ls的最小值
inline bool nroot(int p){return t[t[p].f].son[0]==p||t[t[p].f].son[1]==p;}
inline void update_set(int p){t[p].hfls=fir(h[p]);}
inline void update(int p)
{
int lc=t[p].son[0],rc=t[p].son[1];
t[p].s=1+t[lc].s+t[rc].s;
int w=min(t[p].w,t[p].hfls);
int L=min(w,t[lc].rs+1);
int R=min(w,t[rc].ls);
t[p].ls=min(t[lc].ls,t[lc].s+R+1);//t[p].ls一定含链最上面那个点
t[p].rs=min(t[rc].rs,t[rc].s+L);//t[p].rs一定含链最下面那个点
}
void rotate(int p,int w)
{
int f=t[p].f,gf=t[f].f;
int r=t[p].son[w],R=f;t[R].son[w^1]=r;if(r)t[r].f=R;
r=p;R=gf;if(nroot(f))t[R].son[t[R].son[1]==f]=r;t[r].f=R;
r=f;R=p;t[R].son[w]=r;t[r].f=R;update(f),update(p);
}
void splay(int p)
{
while(nroot(p))
{
int f=t[p].f,gf=t[f].f;
if(!nroot(f))rotate(p,t[f].son[0]==p);
else
{
if(t[f].son[0]==p&&t[gf].son[0]==f)rotate(f,1),rotate(p,1);
else if(t[f].son[0]==p&&t[gf].son[1]==f)rotate(p,1),rotate(p,0);
else if(t[f].son[1]==p&&t[gf].son[0]==f)rotate(p,0),rotate(p,1);
else rotate(f,0),rotate(p,0);
}
}
}
void access(int x)
{
for(int y=0;x;x=t[y=x].f)
{
splay(x);if(t[x].son[1])h[x].insert(t[t[x].son[1]].ls);
if(y)h[x].erase(h[x].find(t[y].ls));
t[x].son[1]=y;
update_set(x);update(x);
}
}
int n;
void query(int x)
{
access(x);splay(x);
if(t[x].rs>n)puts("-1");
else qw(t[x].rs),puts("");
}
void change(int x)
{
access(x);splay(x);
t[x].w?t[x].w=0:t[x].w=inf;
update(x);
}
struct edge{int x,y,next;}a[N<<1];int len,last[N];
void ins(int x,int y){a[++len]=(edge){x,y,last[x]};last[x]=len;}
void maketree(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y==t[x].f)continue;
t[y].f=x;maketree(y);
h[x].insert(t[y].ls);
}
update_set(x);update(x);
}
int main()
{
qr(n);
for(int i=0;i<=n;i++)t[i].w=t[i].ls=t[i].rs=inf;
for(int i=1;i<=n-1;i++){int x,y;qr(x);qr(y);ins(x,y);ins(y,x);}
maketree(1);
int m;qr(m);
while(m--)
{
int opt,x;qr(opt),qr(x);
if(!opt)change(x);
else query(x);
}
return 0;
}
Qtree6思路
貌似这道题不用开 m u l t i s e t multiset multiset,真的是太好了!
先仔细想想维护吧,因为要求编号为 x x x的点相连通的点的个数(定义两个点 x x x, y y y连通为 x x x到 t t t的路径上所有点的颜色相同,包括 x x x和 y y y)
貌似不怎么好搞,如果暴力删边连边,菊花图卡爆了。
开两颗 L C T LCT LCT,分别代表黑色和白色,应该可行。
但是如何维护,是个要点。先考虑一下如何连边。
既然要考虑权的唯一性,那么可以考虑点权转边,如果一个点 p p p为白色,那么在白色 L C T LCT LCT上,与 p p p在原树的父亲建一条虚边,若构成连通图的话,就对答案有贡献。
询问答案时,找到所在的原树根节点,由于根节点的父亲不在 L C T LCT LCT中,那么就说明根节点的 c o l col col不为 L C T LCT LCT的颜色,此时需要将根节点旋上辅助树的根( s p l a y ( r t ) splay(rt) splay(rt))上,输出根节点的右儿子的答案,即可。
但是如何维护答案?
由于对于一个点 x x x,它有多个儿子,但只有一个儿子在 S p l a y Splay Splay上,要多开一个数组来储存虚儿子的数目 c c c。
贴一个代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#define gc getchar()
using namespace std;
const int N=1e5+10;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
int fa[N],col[N];
struct LCT
{
struct node{int f,son[2],c,s;}t[N];
LCT(){for(int i=1;i<N;i++)t[i].s=1;}
inline bool nroot(int p){return t[t[p].f].son[0]==p||t[t[p].f].son[1]==p;}
inline void update(int p){t[p].s=t[t[p].son[0]].s+t[t[p].son[1]].s+t[p].c+1;}//c为虚
void rotate(int p,int w)
{
int f=t[p].f,gf=t[f].f;
int r=t[p].son[w],R=f;t[R].son[w^1]=r;if(r)t[r].f=R;
r=p;R=gf;if(nroot(f))t[R].son[t[R].son[1]==f]=r;t[r].f=R;
r=f;R=p;t[R].son[w]=r;t[r].f=R;update(f),update(p);
}
void splay(int p)
{
while(nroot(p))
{
int f=t[p].f,gf=t[f].f;
if(!nroot(f))rotate(p,t[f].son[0]==p);
else
{
if(t[f].son[0]==p&&t[gf].son[0]==f)rotate(f,1),rotate(p,1);
else if(t[f].son[0]==p&&t[gf].son[1]==f)rotate(p,1),rotate(p,0);
else if(t[f].son[1]==p&&t[gf].son[0]==f)rotate(p,0),rotate(p,1);
else rotate(f,0),rotate(p,0);
}
}
}
void access(int x)
{
for(int y=0;x;x=t[y=x].f)
splay(x),t[x].c+=t[t[x].son[1]].s,t[x].c-=t[t[x].son[1]=y].s;
}
int findroot(int x)
{
access(x);splay(x);
while(t[x].son[0])x=t[x].son[0];
splay(x);
return x;
}
void link(int x)
{
splay(x);
int y=t[x].f=fa[x];
access(y);splay(y);
t[y].c+=t[x].s,t[y].s+=t[x].s;
}
void cut(int x)
{
access(x);splay(x);
t[x].son[0]=t[t[x].son[0]].f=0;
update(x);
}
}lct[2];
struct edge{int x,y,next;}a[N<<1];int len,last[N];
inline void ins(int x,int y){a[++len]=(edge){x,y,last[x]};last[x]=len;}
void dfs(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;if(y==fa[x])continue;
fa[y]=x;
dfs(y);
lct[0].link(y);
}
}
int main()
{
len=0;
int n;qr(n);
for(int i=1;i<n;i++)
{
int x,y;qr(x),qr(y);
ins(x,y);ins(y,x);
}
dfs(1);fa[1]=n+1;
lct[0].link(1);
int m;qr(m);
while(m--)
{
int opt,x;qr(opt),qr(x);
if(opt)lct[col[x]].cut(x),lct[col[x]=!col[x]].link(x);
else
{
int rt=lct[col[x]].findroot(x);
qw(lct[col[x]].t[lct[col[x]].t[rt].son[1]].s);puts("");
}
}
return 0;
}
Qtree7 思路
和Qtree6差不多吧。
不过开多一个multiset来存虚儿子的信息即可。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<set>
#define gc getchar()
using namespace std;
const int N=1e5+10;
const int inf=2147483647;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
int fa[N],col[N],d[N];
struct LCT
{
multiset<int>h[N];
int fir(multiset<int>&s){return s.size()?*s.rbegin():-inf;}
struct node{int f,son[2],ms,hfms;}t[N];
LCT(){for(int i=0;i<N;i++)t[i].ms=t[i].hfms=-inf;}
inline bool nroot(int p){return t[t[p].f].son[0]==p||t[t[p].f].son[1]==p;}
inline void update_set(int p){t[p].hfms=fir(h[p]);}
inline void update(int p)
{
int lc=t[p].son[0],rc=t[p].son[1];
t[p].ms=max(t[lc].ms,max(t[rc].ms,max(t[p].hfms,d[p])));
}
void rotate(int p,int w)
{
int f=t[p].f,gf=t[f].f;
int r=t[p].son[w],R=f;t[R].son[w^1]=r;if(r)t[r].f=R;
r=p;R=gf;if(nroot(f))t[R].son[t[R].son[1]==f]=r;t[r].f=R;
r=f;R=p;t[R].son[w]=r;t[r].f=R;update(f),update(p);
}
void splay(int p)
{
while(nroot(p))
{
int f=t[p].f,gf=t[f].f;
if(!nroot(f))rotate(p,t[f].son[0]==p);
else
{
if(t[f].son[0]==p&&t[gf].son[0]==f)rotate(f,1),rotate(p,1);
else if(t[f].son[0]==p&&t[gf].son[1]==f)rotate(p,1),rotate(p,0);
else if(t[f].son[1]==p&&t[gf].son[0]==f)rotate(p,0),rotate(p,1);
else rotate(f,0),rotate(p,0);
}
}
}
void access(int x)
{
for(int y=0;x;x=t[y=x].f)
{
splay(x);if(t[x].son[1])h[x].insert(t[t[x].son[1]].ms);
if(y)h[x].erase(h[x].find(t[y].ms));
t[x].son[1]=y;update_set(x);update(x);
}
}
int findroot(int x)
{
access(x);splay(x);
while(t[x].son[0])x=t[x].son[0];
splay(x);
return x;
}
void link(int x)
{
splay(x);
int y=t[x].f=fa[x];
access(y);splay(y);
t[y].son[1]=x;update(x);update(y);
}
void cut(int x)
{
access(x);splay(x);
t[x].son[0]=t[t[x].son[0]].f=0;
update(x);
}
void change(int x)
{
access(x);splay(x);
qr(d[x]);update(x);
}
}lct[2];
struct edge{int x,y,next;}a[N<<1];int len,last[N];
inline void ins(int x,int y){a[++len]=(edge){x,y,last[x]};last[x]=len;}
void dfs(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;if(y==fa[x])continue;
fa[y]=x;dfs(y);
}
lct[col[x]].link(x);
}
int main()
{
len=0;
int n;qr(n);
for(int i=1;i<n;i++)
{
int x,y;qr(x),qr(y);
ins(x,y);ins(y,x);
}
for(int i=1;i<=n;i++)qr(col[i]);
for(int i=1;i<=n;i++)qr(d[i]);
fa[1]=n+1;
dfs(1);
int m;qr(m);
while(m--)
{
int opt,x;qr(opt),qr(x);
if(opt==1)lct[col[x]].cut(x),lct[col[x]=!col[x]].link(x);
else if(opt==0)
{
int rt=lct[col[x]].findroot(x);
qw(lct[col[x]].t[lct[col[x]].t[rt].son[1]].ms);puts("");
}
else if(opt==2)
lct[col[x]].change(x);
}
return 0;
}
/*
7
1 2
1 3
2 4
2 5
3 6
3 7
0 0 0 0 0 0 0
-1 -2 -3 -4 -5 -6 -7
4
0 1
1 1
0 2
0 3
*/