GDKOI2015

时间:2022-03-12 14:54:57

problems

http://gdoi.sysu.edu.cn/wp-content/uploads/2015/03/GDKOI-2015-day1.pdf

http://gdoi.sysu.edu.cn/wp-content/uploads/2015/03/GDKOI-2015-day21.pdf

necklace

回文串问题。

把字符串复制一遍,使得环状变成线状。

然后就是问最长回文串,直接套用manacher算法。

wordcount

网络流问题。

把每个格点(i,j)在网络流中拆分成两个点,这两个点之间连一条流量为cnt[i][j]的边,其中左边的称为入点,右边的称为出点。

GDKOI2015
然后对于格点(i,j)和他相邻的某个格点(k,l)满足:mat[i][j]和mat[k][l]恰好为单词w的某相邻两位,那么从格点(i,j)的出点连一条边到格点(k,l)的入点,流量为正无穷大。
最后如果格点(i,j)满足:mat[i][j]恰好为单词w的第一个字符,那么就从源点S连一条边到格点(i,j)的入点,流量为正无穷大;如果格点(i,j)满足:mat[i][j]恰好为单词w的最后一个字符,那么就从格点(i,j)的入点连一条边到汇点T,流量为正无穷大。
circle
欧拉回路问题。
我们发现以下的性质:
(Ⅰ)如果N为奇数那么无解。
      证明:
      假设N为奇数。
      考虑到达0前的点A,必定为下面两个方程的解的其中一个:
      2A%N=0
      (2A+1)%N=0
      容易知道第一个方程的解为0(舍去),第二个方程的解为N/2。所以A=N/2。
      考虑到达N-1前的点B,同理得B=N/2。
      因为A=B,不符合条件,所以N为奇数时无解。
      所以接下来讨论的都是N为偶数的情况。
(Ⅱ)X(0<=X<=N/2-1)连向2X和2X+1;X+N/2连向2X和2X+1。
(Ⅲ)有且仅有X和X+N/2连向2X;有且仅有X和X+N/2连向2X+1。
总结上面如图所示:
GDKOI2015
我们发现每个点有另外一个点,满足他们的出边和入边完全相同。
我们将这N/2对点合并,并删除重边,那么新图有N/2个点,N条边,并且每个点只有2条出边,2条入边。
我们要恰好经过新图中每个点两次,这等价于恰好经过每条边一次。
“恰好经过每条边一次”这恰好就是欧拉回路。
要求字典序最大只需要在DFS时贪心一下即可。
参考程序:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional> using namespace std; typedef long long LL;
typedef double DB;
typedef pair<int,int> PII; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b) for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int dblcmp(DB x){if(abs(x)<EPS)return ;return(x>)?:-;} inline void SetOpen(string s)
{
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
} inline int Getin_Int()
{
int res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
}
inline LL Getin_LL()
{
LL res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
} const int maxN=; int N;
vector<int> edge[maxN/+],ans; inline int DFS(int x)
{
int now=x;
x%=N/;
while(!edge[x].empty())
{
int y=edge[x].back();
edge[x].pop_back();
DFS(y);
}
ans.push_back(now);
} int main()
{
SetOpen("circle");
int i;
N=Getin_Int();
if(N&){puts("-1\n");return ;}
re(i,,N/-){edge[i].push_back(*i);edge[i].push_back(*i+);}
DFS();
red(i,ans.size()-,)printf("%d ",ans[i]);printf("\n");
return ;
}
tree
数据结构问题。
首先使用DFS序,这样每棵子树在线段树中都是连续的区间,不妨设点u的子树在线段树中的区间为[l[u],r[u]]。
建C棵线段树,第i棵线段树中记录当前节点到根节点的路径中颜色为i的点的权值和。
对于3种不同的命令的做法:
Change u x y:交换第x棵线段树和第y棵线段树中属于区间[l[u],r[u]]的若干个结点(因为要交换,所以线段树用,不过要注意的一点是,u的父亲到根节点的路径中,颜色为x的点的权值和 与 颜色为y的点的权值和 是不一样的,因此要加减 他们的差。

Ask u v c:先求出lca,然后在第c棵中查询:u到根节点的路径中颜色为c的点的权值和+u到根节点的路径中颜色为c的点的权值和-lca到根节点的路径中颜色为c的权值和-lca的父亲到根节点的路径中颜色为c的权值和

Set u c val:建设u原来的颜色是d,原来的权值为f,将第d棵线段树中属于区间[l[u],r[u]]的节点都减去f;然后在第c线段树中属于区间[l[u],r[u]]的结点都加上val。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional> using namespace std; typedef long long LL;
typedef double DB;
typedef pair<int,int> PII; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b) for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int dblcmp(DB x){if(abs(x)<EPS)return ;return(x>)?:-;} inline void SetOpen(string s)
{
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
} inline int Getin_Int()
{
int res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
}
inline LL Getin_LL()
{
LL res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
} const int maxN=;
const int maxM=;
const int maxC=; int N,M,C;
int c[maxN+],v[maxN+];
int first[maxN+],now;
struct Tedge{int v,next;}edge[*maxN+];
int fa[maxN+],dep[maxN+];
int jump[maxN+][];
int sum[maxN+][maxC+];
int id[maxN+],l[maxN+],r[maxN+],cnt; inline void addedge(int u,int v)
{
now++;
edge[now].v=v;
edge[now].next=first[u];
first[u]=now;
} int que[maxN+],head,tail;
inline void BFS(int S)
{
mmst(fa,-);
que[head=tail=]=S;
fa[S]=;
dep[S]=;
while(head<=tail)
{
int u=que[head++],i,v;
for(i=first[u],v=edge[i].v;i!=-;i=edge[i].next,v=edge[i].v)if(v!=fa[u])
{
que[++tail]=v;
fa[v]=u;
dep[v]=dep[u]+;
}
}
} int sta[maxN+],top;
int last[maxN+];
inline void DFS(int S)
{
int j;
re(j,,N)last[j]=first[j];
sta[top=]=S;
id[S]=cnt=;
while(top>=)
{
int u=sta[top],&i=last[u],v;
for(v=edge[i].v;i!=-;i=edge[i].next,v=edge[i].v)if(!id[v])
{
id[v]=++cnt;
sta[++top]=v;
break;
}
if(i==-)top--;
}
} inline void swim(int &x,int H)
{
int i;
for(i=;H!=;H/=,i++)if(H&)x=jump[x][i];
}
inline int Ask_LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
swim(x,dep[x]-dep[y]);
if(x==y)return x;
int i;
red(i,-,)if(jump[x][i]!=jump[y][i]){x=jump[x][i];y=jump[y][i];}
return jump[x][];
} struct Ttree
{
Ttree *l,*r;
int add,v;
}*tree[maxC+]; inline Ttree *NewTtree()
{
Ttree *res=new Ttree;
res->l=res->r=;
res->add=res->v=;
return res;
} inline void down(Ttree *&root,int l,int r,int mid)
{
if(root->add==)return;
int add=root->add;root->add=;
if(l==r)return;
if(!root->l)root->l=NewTtree();
if(l==mid) root->l->v+=add;
root->l->add+=add;
if(!root->r)root->r=NewTtree();
if(mid+==r) root->r->v+=add;
root->r->add+=add;
} inline void update(Ttree *&root,int l,int r,int x,int y,int v)
{
if(!root) root=NewTtree();
if(l>r || y<l || r<x)return;
int mid=(l+r)/;
down(root,l,r,mid);
if(x<=l && r<=y)
{
if(l==r)root->v+=v;
root->add+=v;
return;
}
update(root->l,l,mid,x,y,v);
update(root->r,mid+,r,x,y,v);
} inline void change(Ttree *&R1,Ttree *&R2,int l,int r,int x,int y,int temp1,int temp2)
{
if(!R1) R1=NewTtree();
if(!R2) R2=NewTtree();
if(l>r || y<l || r<x) return;
int mid=(l+r)/;
down(R1,l,r,mid);
down(R2,l,r,mid);
if(x<=l && r<=y)
{
if(l==r)R1->v+=-temp1+temp2;R1->add+=-temp1+temp2;
if(l==r)R2->v+=-temp2+temp1;R2->add+=-temp2+temp1;
swap(R1,R2);
return;
}
change(R1->l,R2->l,l,mid,x,y,temp1,temp2);
change(R1->r,R2->r,mid+,r,x,y,temp1,temp2);
} inline int ask(Ttree *&root,int l,int r,int x)
{
if(!root) root=NewTtree();
if(l>r || x<l || r<x)return ;
int mid=(l+r)/;
down(root,l,r,mid);
if(x<=l && r<=x)return root->v;
if(x<=mid) return ask(root->l,l,mid,x); else return ask(root->r,mid+,r,x);
} int main()
{
SetOpen("tree");
int i,j;
N=Getin_Int();C=;
re(i,,N){c[i]=Getin_Int()+;upmax(C,c[i]);}
re(i,,N)v[i]=Getin_Int();
mmst(first,-);now=-;
re(i,,N-)
{
int x=Getin_Int()+,y=Getin_Int()+;
addedge(x,y);
addedge(y,x);
}
BFS();
re(i,,tail)
{
int u=que[i];
jump[u][]=fa[u];
re(j,,-)jump[u][j]=jump[jump[u][j-]][j-];
}
re(i,,tail)
{
int u=que[i];
re(j,,C)sum[u][j]=sum[fa[u]][j];
sum[u][c[u]]+=v[u];
}
DFS();
red(j,tail,)
{
int u=que[j],v;
l[u]=r[u]=id[u];
for(i=first[u],v=edge[i].v;i!=-;i=edge[i].next,v=edge[i].v)if(v!=fa[u])
{
upmin(l[u],l[v]);
upmax(r[u],r[v]);
}
}
re(i,,N)re(j,,C)update(tree[j],,N,id[i],id[i],sum[i][j]);
M=Getin_Int();
while(M--)
{
char S[];
int a,b,x,y,c,val,lca,temp1,temp2,temp3;
scanf("%s",S);
switch(S[])
{
case 'C':
a=Getin_Int()+;x=Getin_Int()+;y=Getin_Int()+;
temp1=ask(tree[x],,N,id[fa[a]]);
temp2=ask(tree[y],,N,id[fa[a]]);
change(tree[x],tree[y],,N,l[a],r[a],temp1,temp2);
break;
case 'A':
a=Getin_Int()+;b=Getin_Int()+;c=Getin_Int()+;
lca=Ask_LCA(a,b);
printf("%d\n",ask(tree[c],,N,id[a])+ask(tree[c],,N,id[b])-ask(tree[c],,N,id[lca])-ask(tree[c],,N,id[fa[lca]]));
break;
case 'S':
a=Getin_Int()+;c=Getin_Int()+;val=Getin_Int();
re(i,,C)
{
temp1=ask(tree[i],,N,id[a])-ask(tree[i],,N,id[fa[a]]);
if(temp1==) continue;
update(tree[i],,N,l[a],r[a],-temp1);
break;
}
update(tree[c],,N,l[a],r[a],val);
break;
}
}
return ;
}
 
watchdogs
动态规划问题。
将题目的模型简化得到:
 GDKOI2015
上下各有N个点,之间有若干条连线。
选择若干条不相交的直线,任意两条直线不能有公共点,每覆盖一个点都有一个分数(上面为vi,下面为pi),求最大的分数和。
首先对于每条直线按a从小到大排序。
枚举直线:
GDKOI2015
我们发现,如果选择了这条直线,那么a前面的那些点只能连向b前面的点。 
记F[i]表示当前连向的点的最大编号为i时的最大的权值和,注意F是可以随着枚举而不断更新的。
就是说询问F[1..b-1]的最大值。
用树状数组。
然后可以更新F[b].
 
planetcup
枚举进入第一轮比赛的第K名的分数(假设是x)。
容易知道对于0国分数小于x的选手,参加第一轮比赛;对于1国分数小于x的选手,参加第二轮比赛。
所以参加第一轮比赛的选手中,分数小于x的选手都是0国的。
先把0国分数小于x的选手筛出去,他们没有贡献。
剩下的为1国选手和分数大于等于x的0国选手。
将他们按第二轮比赛的成绩从小到大排序。
记F[i][j]表示前i个人,有j个人参加了第一轮比赛且在前K名,容易知道参加的第二轮比赛的人有i-j个。
转移方程容易得到。
参考程序:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional> using namespace std; typedef long long LL;
typedef double DB;
typedef pair<int,int> PII; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b) for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int dblcmp(DB x){if(abs(x)<EPS)return ;return(x>)?:-;} inline void SetOpen(string s)
{
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
} inline int Getin_Int()
{
int res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
}
inline LL Getin_LL()
{
LL res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
} const int maxN=;
const int maxK=maxN/; int N,K;
struct Tdata
{
int x,y,z;
inline void input(){x=Getin_Int();y=Getin_Int();z=Getin_Int();}
}data[maxN+];
int F[maxN+][maxK+];
int ans; inline bool cmpy(Tdata a,Tdata b){return a.y>b.y;} int main()
{
SetOpen("planetcup");
int i,j,k;
N=Getin_Int();K=Getin_Int();
re(i,,N)data[i].input();
sort(data+,data+N+,cmpy);
ans=;
re(k,,N)
{
int p=data[k].x,cnt=;
mmst(F,-);
F[][]=;
re(i,,N-)
{
if(data[i+].z== && data[i+].x<p)
{
re(j,,K)F[i+][j]=F[i][j];
continue;
}
re(j,,K)
{
if(F[i][j]==-)continue;
if(data[i+].z== && data[i+].x<p)
{
if(cnt-j+<=K) upmax(F[i+][j],F[i][j]+data[i+].y); else upmax(F[i+][j],F[i][j]);
continue;
}
if(data[i+].x>=p && j+<=K)
upmax(F[i+][j+],F[i][j]+data[i+].x*data[i+].z);
if(cnt-j+<=K) upmax(F[i+][j],F[i][j]+data[i+].y*data[i+].z); else upmax(F[i+][j],F[i][j]);
}
cnt++;
}
upmax(ans,F[N][K]);
}
cout<<ans<<endl;
return ;
}
 
v
数据结构题。
对于每个点,分别求出其向上递增,递减,先增后减,先减后增的最长序列。
然后运用倍增思想,t[i][j]表示从结点i向上的长为2^i的序列中的答案。
GDKOI2015
设k为i向上跳2^(j-1)步到达的点。
容易知道答案要么全部在红色区域内(答案为t[i][j-1]),要么全部在蓝色区域内(答案为t[k][j-1]),或者跨过红色区域和蓝色区域,这时必然经过k。
有4种情况:
k下方最长的递增序列长度+k上方最长的先增后减序列长度-1
k下方最长的递减序列长度+k上方最长的先减后增序列长度-1
k下方最长的先增后减序列长度+k上方最长的递减序列长度-1
k下方最长的先减后增序列长度+k上方最长的递增序列长度-1
对于询问u,v:
先求出lca。
那么有2种情况,经过lca和不经过lca。
经过lca可以类似于上面的4种情况讨论。
不经过lca,就是从u到lca或者从v到lca,不失一般性,讨论从u到lca :
GDKOI2015
我们把从u到lca的路径分成若干段,其中每段的长度都是2的若干次方,可以证明不超过logn段。
在每段内部,我们已经预处理好了,剩下的就是段与段之间的合并,还是利用上面的4种情况进行讨论。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional> using namespace std; typedef long long LL;
typedef double DB;
typedef pair<int,int> PII; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b) for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int dblcmp(DB x){if(abs(x)<EPS)return ;return(x>)?:-;} inline void SetOpen(string s)
{
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
} inline int Getin_Int()
{
int res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
}
inline LL Getin_LL()
{
LL res=,flag=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return res*flag;
} const int maxN=; int N,Q;
int first[maxN+],now;
struct Tedge{int v,next;}edge[*maxN+];
int fa[maxN+],dep[maxN+];
int jump[maxN+][];
int p[maxN+][];//0上升 1下降 2先上后下 3先下后上
int t[maxN+][];
int ans; inline void addedge(int u,int v)
{
now++;
edge[now].v=v;
edge[now].next=first[u];
first[u]=now;
} int que[maxN+],head,tail;
inline void BFS(int S)
{
dep[que[head=tail=]=S]=;
while(head<=tail)
{
int u=que[head++],i,v;
for(i=first[u],v=edge[i].v;i!=-;i=edge[i].next,v=edge[i].v)dep[que[++tail]=v]=dep[u]+;
}
} inline int swim(int x,int H)
{
for(int i=;H!=;H/=,i++)if(H&)x=jump[x][i];
return x;
}
inline int Ask_LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
x=swim(x,dep[x]-dep[y]);
if(x==y)return x;
int i;
red(i,,)if(jump[x][i]!=jump[y][i]){x=jump[x][i];y=jump[y][i];}
return jump[x][];
} inline int up(int x,int y,int f)
{
return min(p[x][f],dep[x]-dep[y]+);
}
inline int down(int x,int y,int f)
{
int l=,r=dep[x]-dep[y],mid;
while(l<=r)
{
mid=(l+r)/;
int temp=swim(x,mid);
if(p[temp][f]>=dep[temp]-dep[y]+) r=mid-; else l=mid+;
}
return dep[swim(x,l)]-dep[y]+;
} inline int solve(int a,int b)
{
int i,res=,H=dep[a]-dep[b]+,x=a,y;
for(i=;H!=;H/=,i++)if(H&)
{
y=swim(x,(<<i)-);
upmax(res,t[x][i]);
if(a!=x)
{
upmax(res,down(a,x,)+up(x,y,)-);
upmax(res,down(a,x,)+up(x,y,)-);
upmax(res,down(a,x,)+up(x,y,)-);
upmax(res,down(a,x,)+up(x,y,)-);
}
x=fa[y];
}
return res;
} int main()
{
SetOpen("v");
int i,j;
N=Getin_Int();
mmst(first,-);now=-;
re(i,,N){fa[i]=Getin_Int();addedge(fa[i],i);}
BFS();
re(i,,)jump[][i]=;
re(j,,tail)
{
int u=que[j];
jump[u][]=fa[u];
re(i,,)jump[u][i]=jump[jump[u][i-]][i-];
}
re(j,,tail)
{
int u=que[j];
if(u<fa[u])p[u][]=p[fa[u]][]+; else p[u][]=;
if(u>fa[u])p[u][]=p[fa[u]][]+; else p[u][]=;
p[u][]=p[u][];if(u<fa[u])p[u][]=max(p[fa[u]][],p[fa[u]][])+;
p[u][]=p[u][];if(u>fa[u])p[u][]=max(p[fa[u]][],p[fa[u]][])+;
}
re(j,,tail)
{
int a=que[j],c,d;
t[a][]=;
re(i,,)
{
c=jump[a][i-];
d=swim(c,dep[a]-dep[c]-);
t[a][i]=max(t[a][i-],t[c][i-]);
upmax(t[a][i],down(a,c,)+up(c,d,)-);
upmax(t[a][i],down(a,c,)+up(c,d,)-);
upmax(t[a][i],down(a,c,)+up(c,d,)-);
upmax(t[a][i],down(a,c,)+up(c,d,)-);
}
}
ans=;
Q=Getin_Int();
while(Q--)
{
int u=Getin_Int()^ans,v=Getin_Int()^ans,lca;
ans=;
lca=Ask_LCA(u,v);
upmax(ans,solve(u,lca));
upmax(ans,solve(v,lca));
upmax(ans,down(u,lca,)+down(v,lca,)-);
upmax(ans,down(u,lca,)+down(v,lca,)-);
upmax(ans,down(u,lca,)+down(v,lca,)-);
upmax(ans,down(u,lca,)+down(v,lca,)-);
printf("%d\n",ans);
}
return ;
}
avenger
待续......

GDKOI2015的更多相关文章

  1. GDKOI2015 Day2

    P1 题目描述: 给出一个二分图,选择互不相交的边,使得边覆盖的点权和最大. solution: 简单DP,用树状数组维护最大值. 时间复杂度:$O(n \log n) $ P2 题目描述: 给出N个 ...

  2. GDKOI2015 Day1

    P1 题目描述: 判断一个环形字符串(或者减去一个字符之后)是否是回文串 solution: 1.hash 将字符串的前缀进行hash,然后将字符串翻转,再做一次hash,然后枚举对称轴,判断两边的h ...

  3. GDKOI2015滚粗记

    又是愉悦的滚粗了hahaha(特别不甘心啊啊啊) 其实去比赛每次都一样啦,就是每次吃饭睡觉补番考试评讲互黑跪烂什么的,这次就不用说了啦,先把老师要求写的东西贴出来再写点别的啦 这次暴露了很多问题,首先 ...

  4. GDKOI 2015 Day1 T2 单词统计Pascal

    我虽然没有参加GDKOI2015,但是我找了2015年的题练了一下. 题意如下: 思路:最大流,因为有多组数据,每次读入一组数据都要清零. a. 将每个点拆分成两个点,例如样例G→G`,再将字母一一编 ...

  5. GDOI2016酱油记(补发)

    这篇酱油记是前年发在MCHacker一个叫code-hub的博客上的(已崩),现在来补发一下... GDOI2016扯淡(爆零记) 大家好,我是巨弱DCDCBigBig,在五一期间和一群神牛去考GDO ...

随机推荐

  1. 笔记002:javascript简介

    1. HTML服务于内容 CSS服务于表现 Javascript服务于行为(一切东西的粘合剂) 2.javascript能运行多种宿主环境中(Web浏览器最普遍) 3.历史 1995 Netscape ...

  2. 电赛总结(二)&mdash&semi;&mdash&semi;AD芯片总结之AD7715

    一.特性参数 1.16位无失真AD转换器 2.增益可调,在1,2,32,128可切换. 3.数字地和模拟地分开,可以减少噪声. 4.具有较大的输出电流,有比较好的带载能力. 二.管脚排列 三.引脚功能 ...

  3. Mysql JOIN优化。

    join性能自行百度,google 数据60w+,这里我只测试了一个limit , ) ,) AS C LEFT JOIN table2 AS B ON C.e_id=B.id; ) ,;

  4. 启动eclipse时出现&OpenCurlyDoubleQuote;Failed to load the JNI shared library jvm&period;dll”错误及解决

    昨晚安装另一个版本的eclipse,启动时出现了"Failed to load the JNI shared library jvm.dll"错误: 1.刚开始以为是因为当时没有将 ...

  5. JavaWeb小项目(一)

    总结一下前段时间,在学了JSP.Servlet.JavaBean后,配合Tomcat服务器加上MySQl数据库搭的第一个简单网站. 前前后后,在学习了以上说的这些概念知识后,还进一步熟悉了整个搭建的流 ...

  6. Python-递归、三元表达式列表生成式等

    一.函数递归 1.什么是函数递归:函数的递归调用是函数嵌套的一种特殊形式,在调用一个函数的过程中又直接或者间接地调用该函数本身,称之为函数的递归调用 2.递归调用必须明确的两个阶段: 1.回溯:一次次 ...

  7. pyglet--旋转的矩形

    展示怎么制作动画.... #-*- coding:utf-8 -*- from pyglet.gl import * from pyglet import clock def draw_rect(x, ...

  8. Sigma Function &lpar;平方数与平方数&ast;2的约数和是奇数&rpar;

    Sigma Function https://vjudge.net/contest/288520#problem/D Sigma function is an interesting function ...

  9. shell 获取脚本的绝对路径

    basepath=$(cd `dirname $0`; pwd) 在此解释下basepath : dirname $0,取得当前执行的脚本文件的父目录 cd `dirname $0`,进入这个目录(切 ...

  10. 一次lvs迁移记录

    需求:从117.119.33.99迁移到122.14.206.125,lvs为dr模式,系统版本为debian7 1.安装lvs和keepalived # aptitude install -y ip ...