水题(指三道题debug了接近一天),T4摆烂了
T1初中数学题
大意
∏(ai^2+bi^2)=x^2+y^2,输入正整数ai,bi,输出正整数x,y
思路
直接把答案算出来后暴力枚举肯定是不行的,所以ai和bi能对我们的答案有提示。尝试思考数学方法。当n=2时如何求解。化简
$$
原式=a1^2a2^2+a1^2b2^2+b1^2a2^2+b1^2b2^2 =(a1a2+b1b2)^2+(a1b2-b1a2)^2
$$
这样(a1^2+b1^2)(a2^2+b2^2)=x^2+y^2 可求出一组x,y。当n>=2时,把每次求出的x,y作为a1,a2递推就行了。
T2你不会的博弈论
大意
一开始他们有一个长度为 的序列 n的序列满足不严格单调递增 。现在异客和史尔特尔将要轮流进要轮流进行操作,每次操作可以选中一个数并将其减去一个正整数,操作完之后序列必须还要满足上述性质。由于异客获得了人民的力量,他获得了 q次修改序列的权利,具体来说,他每次可以在序列前面或后面加入一个数字(加入后保证仍然满足上述性质)。那么先手胜还是后手胜?
思路
先求差分。更改一个数之后只会改变差分数组里的两个值,且改变量的绝对值相等。这个问题就转化为阶梯博弈(Nim博弈的变式),即有n堆石子,我们可以从第i堆石子取若干个移动到第i-1堆里,第一堆的石子被取走后就不再出现在游戏中。当无石子可取(即第一堆无石子)时,失败。
结论:当奇数堆的Nim和为0时必败,大于0时必胜。
证明:
若石子都被取完,奇数堆Nim和=0
若奇数堆Nim和=0,则一次操作后,Nim和一定不为0
若奇数堆Nim和!=0,则一次操作后,可保证Nim和为0
动态维护奇数堆Nim和即可。
T3 简单的树上距离
大意
给定一棵 n个节点的边权全部为正整数的树以及q次询问,每次询问给出四个参数l1,r2,l2,r2 ,满足 。对于每次询问,设点集A为所有编号在[l1,r1]内的点,B为所有编号在[l2,r2]内的点。求从点集A和B中各选一个点,能形成的最大距离。T=10,1<=n,q<=3e3
思路
树链剖分(求 LCA)。
结论:若点集A中a1,b1,两点形成最大距离,点集B中a2,b2,两点形成最大距离,则点集A,B中各选一个点形成最大距离一定是a1,b1,a2,b2以这四个数中的两个数为端点。(感性理解)。
用线段树维护一个区间[l,r]点集中的最大距离,保存这个距离的两端点,push up时最大距离的候选项有6个:x.dat;y.dat,juli(x.F,y.F),juli(x.F,y.S),juli(x.S,y.F),juli(x.S,y.S);
。
我写的BUG(DE了将近一天)
-
建双向边,数组大小没开N<<1
-
树链剖分写挂了(写成了点剖分)
-
ask函数中,当只递归一个儿子,x,y只有一个有值时,这时merge(x,y)就会出错,可能merge出来的是没有值的。
-
对于每一次询问,ask(l1,r1),ask(l2,r2),得到的答案不能merge,因为merge函数求的是整个点集的最大距离,而询问的是两个点集各选一个点形成的最大距离。
上
#include<bits/stdc++.h>
using namespace std;
#define fuck puts("fuck");
#define int long long
const int MAXN=1e5+10;
int _,n,q;
int tot,fa[MAXN],size[MAXN],son[MAXN],top[MAXN],dep[MAXN],dis[MAXN];
int ccf,head[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1];
template<typename W>inline void rd(W &x){
W ch=getchar(),tx=1;x=0;
while(!isdigit(ch)) tx=ch=='-'?-1:tx,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x=tx*x;
}
void dfs1(int x,int dad){
size[x]=1;
dep[x]=dep[fa[x]=dad]+1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=dad){
dis[y]=dis[x]+val[i];
dep[y]=dep[x]+1;
dfs1(y,x);
if(size[y]>size[son[x]])
son[x]=y;
size[x]+=size[y];
}
}
}
void dfs2(int x){
if(son[fa[x]]==x)
top[x]=top[fa[x]];
else top[x]=x;
if(son[x])
dfs2(son[x]);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=fa[x]&&y!=son[x])
dfs2(y);
}
}
inline int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y])
swap(x,y);
return y;
}//树剖LCA
inline int juli(int x,int y){
return dis[x]+dis[y]-2*dis[LCA(x,y)];
}
struct node{int F,S,dat;};
class Seg_Tre{
private:
node a[MAXN<<2];
int L[MAXN<<2],R[MAXN<<2];
#define lid id<<1
#define rid id<<1|1
public:
inline node merge(node x,node y){
node ans;
int j1,j2,j3,j4;
if(x.F==0) return y;
if(y.F==0) return x;//只有一个有值的时候merge个屁
ans=(x.dat>y.dat)?x:y;
j1=juli(x.F,y.F); j2=juli(x.F,y.S);
j3=juli(x.S,y.F); j4=juli(x.S,y.S);
if(ans.dat<j1) ans={x.F,y.F,j1};
if(ans.dat<j2) ans={x.F,y.S,j2};
if(ans.dat<j3) ans={x.S,y.F,j3};
if(ans.dat<j4) ans={x.S,y.S,j4};
return ans;
}
void build(int id,int l,int r){
L[id]=l,R[id]=r;
if(l==r){
a[id].F=a[id].S=l;
a[id].dat=0;
return;
}
int mid=l+r>>1;
build(lid,l,mid);
build(rid,mid+1,r);
a[id]=merge(a[lid],a[rid]);
return;
}
node ask(int id,int l,int r){
if(l<=L[id]&&r>=R[id])
return a[id];
int mid=L[id]+R[id]>>1;
node x=(node){0,0,0},y=(node){0,0,0};//
if(l<=mid)
x=ask(lid,l,r);
if(r>mid)
y=ask(rid,l,r);
return merge(x,y);
}
}tree;
inline void add(int u,int v,int w){
to[++ccf]=v;
val[ccf]=w;
nxt[ccf]=head[u];
head[u]=ccf;
}
inline void init(){
rd(n),rd(q);
int u,v,w;
for(int i=1;i<n;++i){
rd(u),rd(v),rd(w);
add(u,v,w);add(v,u,w);
}
dfs1(1,0);
dfs2(1);
tree.build(1,1,n);
}
inline void work(){
int l1,r1,l2,r2;
node x,y,ans;
while(q--){
rd(l1),rd(r1),rd(l2),rd(r2);
x=tree.ask(1,l1,r1);
y=tree.ask(1,l2,r2);
int j1,j2,j3,j4;
j1=juli(x.F,y.F); j2=juli(x.F,y.S);
j3=juli(x.S,y.F); j4=juli(x.S,y.S);//不能merge
ans={x.F,y.F,j1};
if(ans.dat<j2) ans={x.F,y.S,j2};
if(ans.dat<j3) ans={x.S,y.F,j3};
if(ans.dat<j4) ans={x.S,y.S,j4};
printf("%lld\n",ans.dat);
}
}
signed main(){
freopen("wanted.in","r",stdin);
freopen("wanted.out","w",stdout);
init();
work();
return !~(0^_^0);
}
/*
5 6
4 2 4
2 1 3
4 3 6
2 5 1
1 2 3 4
1 1 2 3
1 1 2 5
2 3 4 5
4 4 5 5
1 2 4 5
*/