void build(int root,int l,int r)
{
int mid=l+r>>1;
if (l==r) {
tree[root].zhi=read();return;}
build(root<<1,l,mid);
build((root<<1)+1,mid+1,r);
tree[root].zhi=tree[root<<1].zhi+tree[root<<1|1].zhi;
}
void growl(int root,int l,int r)
{
if(k2r)
return;
if(k1<=l&&k2>=r)
{tree[root].add++;tree[root].lazy++;return;}
int mid=(l+r)/2;
int delta=tree[root].lazy;
tree[root*2].lazy+=delta;
tree[root*2].add+=delta;
tree[root*2+1].add+=delta;
tree[root*2+1].lazy+=delta;
tree[root].lazy=0;
growl(root*2,l,mid);
growl(root*2+1,mid+1,r);
tree[root].add=max(tree[root*2].add,tree[root*2+1].add);
}
int find(int root,int l,int r)
{
if(k2r)
return -1;
if(k1<=l&&k2>=r)
return tree[root].add;
int mid=(l+r)/2;
int delta=tree[root].lazy;
tree[root*2].lazy+=delta;
tree[root*2].add+=delta;
tree[root*2+1].add+=delta;
tree[root*2+1].lazy+=delta;
tree[root].lazy=0;
return max(find(root*2,l,mid),find(root*2+1,mid+1,r));
}
int mid=(l+r)/2;
int delta=tree[root].lazy;
tree[root*2].lazy+=delta;
tree[root*2].add+=delta;
tree[root*2+1].add+=delta;
tree[root*2+1].lazy+=delta;
tree[root].lazy=0;
咳咳,敲黑板,这段代码可谓是核心中的核心,它帮助我们在做一些其它操作的时候传递了lazy标记,是一节省时间的利器,至于为什么这么写,看到代码之后应该可以秒推,至于最后一句,则是根据不同的需求改的,并没有什么万能的东西,所以需要随机应变的应对。
int gcd(int a,int b)
{
return (b==0)?a:gcd(b,a%b);
}
/*---------------------------------------------第三章:累死人的图论-----------------------------------------------------*/
在我的理解里,图论就是借助图来解决问题,就像数学里的数形结合。
图又分有向图与无向图两种,存储方式也有边表,邻接表与邻接矩阵三种。
从存储方式讲起:
说实话,我更喜欢邻接矩阵,应为他比较具象,构造简单,好理解与应用,但世上总没有十全十美的东西,邻接矩阵也有他的优点与缺点,同样,邻接表也是。
邻接矩阵最大的优点已经阐述过了,他是一种以二维数组为载体,下标为点,数值为权的存储方式,但他有一个致命的缺点导致他在于邻接表的竞争中彻底落了下风:需要二维数组和三重循环暴搜的他,时空复杂度相比邻接表简直是一个天上一个地下。
下面是邻接表(本人语文能力不行,拍图),相对于邻接矩阵,他的优点是以链表与结构体的形式作为载体,所占空间相对小,时间复杂度相对低,且遍历与更改都非常容易,而他的缺点就显得微不足道了:仅仅是比较抽象,构造需要一个简单的函数而已,其中e数组表示变,linkk数组表示便所对应的下标
遍历循环
for(int i=linkk[k];i;i=e[i].next)
for(int i=1;i<=n;i++)
for(int j=V;j>=1;j--)
if(i-d[j]>0)
f[j]=max(f[j],f[i-d[i]]+v[i]);
int lowbit(int k)
{return k&-k}//取出最右边的0(2进制);
void add(int k,int delta)
{
while(k<=n)
{
c[k]+=delta;
k+=lowbit(k);
}
}//使某一个值加/减;
int getsum(int k)
{
int t=0;
while(k>0)
{
t+=c[k];
k-=lowbit(k);
}
return t;
}//求出1~k的区间和;
这三个函数看似非常简单,实则非常简单,相信不用本人解释,各位大牛就已经自己对着图解出来了;
int getfather(int x)
{
return (father[x]==x)? x: father[x]=getfather(father[x]);
}//找到父节点
void relative(int x,int y)
{
x=getfather(x);
y=getfather(y);
if(x==y) return;
father[y]=x;
}//合并
bool check(int x,int y)
{return getfather(x)==getfather(y)}//判断是否在一个集合
#include
using namespace std;
#define C getchar()
#define maxn 500010
#define rep(i,j,p) for(int i=j;i<=p;i++)
#define ri(b) b=read()
inline int read()
{
int x=0;
char ch;
bool flag=true;
for(;ch>'9'||ch<'0';ch=C)
if(ch=='-')
flag=false;
for(;ch>='0'&&ch<='9';ch=C)
x=(x<<3)+(x<<1)+(ch^48);
return flag?x:-x;
}
int father[maxn]={};
int countl[maxn]={};
int before[maxn]={};
int t;
char a;
int si,sj;
int fa,fb;
/*--------------------------------------------定义区-----------------------------------------------------------------*/
void cb()
{
rep(i,1,30000)
{father[i]=i;
before[i]=1;}
}
int getfather(int x)
{
if (father[x]==x)return x;
int y=getfather(father[x]);
countl[x]+=countl[father[x]];
return father[x]=y;
}
void Un(int x,int y)
{
countl[x]+=before[y];
father[x]=y;
before[y]+=before[x];
before[x]=0;
}
/*--------------------------------------------预备区------------------------------------------------------------------*/
void work()
{
ri(t);
rep(i,1,t)
{
a=C;
ri(si),ri(sj);
fa=getfather(si);
fb=getfather(sj);
if(a=='M')
{
Un(fa,fb);
}
else
{
if(fa!=fb)
printf("%d\n",-1);
else
printf("%d\n",abs(countl[si]-countl[sj])-1);
}
}
}
/*--------------------------------------------工作区-------------------------------------------------------------------*/
int main()
{
cb();
work();
return 0;
}