zoukankan      html  css  js  c++  java
  • 2018年12月27日

    今日小结:今天上午复习了一遍平衡树的相关知识点,下午继续做了一下树链剖分和线段树的有关题目,晚上预习了一下主席树,然后今天做了8道题,然而,两道水题……明天只要攻主席树和平衡树。

    一. 完成的题目:

    SP1043,洛谷P2434,洛谷P3078,洛谷P2025,洛谷P2486,洛谷P3979,CF616D,洛谷P2253

    二.

    1.当日完成题目数:8道。

    2. 未完成6个题目的原因:

    3. 复习的知识点:树链剖分,线段树,主席树,平衡树

    4.不会题目:SP6779

    三:

    1. SP1043 GSS1 - Can you answer these queries I

    题目描述

    给出了序列(A[1],A[2],…,A[N]。 (a[i]≤15007,1≤N≤50000))。查询定义如下: 查询((x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y})。 给定M个查询,程序必须输出这些查询的结果。

    输入输出格式

    输入格式:

    • 输入文件的第一行包含整数(N)
    • 在第二行,(N)个数字跟随。
    • 第三行包含整数(M)
    • (M)行跟在后面,其中第(1)行包含两个数字(x_i)(y_i)

    输出格式:

    您的程序应该输出(M)查询的结果,每一行一个查询。

    输入输出样例

    输入样例#1:

    3 
    -1 2 3
    1
    1 2
    

    输出样例#1:

    2
    

    思路:一道线段树维护区间最大字段和的裸题,就是分三种情况讨论,完全在左子树,完全在右子树,或在左右子树之间。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #define maxn 50007
    #define ls rt<<1
    #define rs rt<<1|1
    using namespace std;
    inline int qread() {
      char c=getchar();int num=0,f=1;
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) num=num*10+c-'0';
      return num*f;
    }
    int n,m;
    struct Tree {
      int lmax,rmax,sum,maxx;
    }tree[maxn<<2];
    inline void pushup(int rt) {
      tree[rt].lmax=max(tree[ls].lmax,tree[ls].sum+tree[rs].lmax);
      tree[rt].rmax=max(tree[rs].rmax,tree[rs].sum+tree[ls].rmax);
      tree[rt].maxx=max(tree[ls].rmax+tree[rs].lmax,max(tree[ls].maxx,tree[rs].maxx));
      tree[rt].sum=tree[ls].sum+tree[rs].sum;
    }
    void build(int rt, int l, int r) {
      if(l==r) {
      	tree[rt].lmax=tree[rt].rmax=tree[rt].sum=tree[rt].maxx=qread();
      	return;
      }
      int mid=(l+r)>>1;
      build(ls,l,mid);
      build(rs,mid+1,r);
      pushup(rt);
    }
    Tree query(int rt, int l, int r, int L, int R) {
      if(L==l&&r==R) return tree[rt];
      int mid=(l+r)>>1;
      if(L>mid) return query(rs,mid+1,r,L,R);
      else if(R<=mid) return query(ls,l,mid,L,R);
      else {
      	Tree a=query(ls,l,mid,L,mid),b=query(rs,mid+1,r,mid+1,R),c;
      	c.lmax=max(a.lmax,a.sum+b.lmax);
      	c.rmax=max(b.rmax,b.sum+a.rmax);
      	c.sum=a.sum+b.sum;
      	c.maxx=max(a.rmax+b.lmax,max(a.maxx,b.maxx));
      	return c;
      }
    }
    int main() {
      n=qread();
      build(1,1,n);
      m=qread();
      for(int i=1,x,y;i<=m;++i) {
      	x=qread(),y=qread();
      	printf("%d
    ",query(1,1,n,x,y).maxx);
      }
      return 0;
    }
    

    2. 洛谷 P2434 [SDOI2005]区间

    题目描述

    现给定(n)个闭区间([ai, bi],1<=i<=n)。这些区间的并可以表示为一些不相交的闭区间的并。你的任务就是在这些表示方式中找出包含最少区间的方案。你的输出应该按照区间的升序排列。这里如果说两个区间([a, b])([c, d])是按照升序排列的,那么我们有(a<=b<c<=d)

    请写一个程序:

    读入这些区间;

    计算满足给定条件的不相交闭区间;

    把这些区间按照升序输出。

    输入输出格式

    输入格式:

    第一行包含一个整数(n)(3<=n<=50000),为区间的数目。以下n行为对区间的描述,第i行为对第i个区间的描述,为两个整数(1<=ai<bi<=1000000),表示一个区间([ai, bi])

    输出格式:

    输出计算出来的不相交的区间。每一行都是对一个区间的描述,包括两个用空格分开的整数,为区间的上下界。你应该把区间按照升序排序。

    输入输出样例

    输入样例#1:

    5
    5 6
    1 4
    10 10
    6 9
    8 10
    

    输出样例#1:

    1 4
    5 10
    

    思路:考虑差分,每次输入x和y,于是x的度++,y的度,然后再扫一遍,累积从0到+的就是左端点,从+到0的就是右端点。

    代码:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #define maxn 1000007
    using namespace std;
    int n,a[maxn],b[maxn],num,maxx;
    inline int qread() {
    	char c=getchar();int num=0,f=1;
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) num=num*10+c-'0';
    	return num*f;
    }
    int main() {
    	n=qread();
    	for(int i=1,x,y;i<=n;++i) {
    		x=qread(),y=qread();
    		a[x]++,b[y]++;
    		maxx=max(maxx,max(x,y));
    	}
    	for(int i=1;i<=maxx;++i) {
    		if(!num&&a[i]) printf("%d ",i);
    		num+=a[i]-b[i];
    		if(!num&&b[i]) printf("%d
    ",i);
    	}
    	return 0;
    }
    

    3. 洛谷 P3078 [USACO13MAR]扑克牌型Poker Hands

    题目描述

    Bessie and her friends are playing a unique version of poker involving a deck with N (1 <= N <= 100,000) different ranks, conveniently numbered 1..N (a normal deck has N = 13). In this game, there is only one type of hand the cows can play: one may choose a card labeled i and a card labeled j and play one card of every value from i to j. This type of hand is called a "straight".

    Bessie's hand currently holds a_i cards of rank i (0 <= a_i <= 100000). Help her find the minimum number of hands she must play to get rid of all her cards.

    一个牛有N堆牌,每堆排数量不等。一只牛一次可以将第i张到第j张各打一张出去,问最少几次打完

    输入输出格式

    输入格式:

    • Line 1: The integer N.

    • Lines 2..1+N: Line i+1 contains the value of (a_i).

    输出格式:

    • Line 1: The minimum number of straights Bessie must play to get rid of all her cards.

    输入输出样例

    输入样例#1:

    5 
    2 
    4 
    1 
    2 
    3 
    

    输出样例#1:

    6 
    

    说明

    Bessie can play a straight from 1 to 5, a straight from 1 to 2, a straight from 4 to 5, two straights from 2 to 2, and a straight from 5 to 5, for a total of 6 rounds necessary to get rid of all her cards.

    思路:双倍经验……跟noip2018 Day1T1一样……本来还以为是线段树,所以才点进来。

    代码:

    #include<cstdio>
    #include<cctype>
    #define maxn 100007
    #define ll long long
    using namespace std;
    int n,a[maxn];
    ll ans;
    inline int qread() {
    	char c=getchar();int num=0,f=1;
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) num=num*10+c-'0';
    	return num*f;
    }
    int main() {
    	n=qread();
    	for(int i=1;i<=n;++i) {
    		a[i]=qread();
    		if(a[i]>a[i-1]) ans+=a[i]-a[i-1];
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    4. 洛谷 P2025 脑力大人之监听电话

    题目背景

    画外音:

    (声明:不要管前面那个,纯属意外,现已经重新编题,绝对原创)

    上次海选,我们选出了参赛者中的20%参加本次比赛,现在我们将进行第二轮的筛选,这次的比赛将更加残酷。每25人为一组,其中的第一名将直接进入下一轮,而第4名以后的人(不包括第4名)将被直接淘汰。第2-4名将参加接下来的加赛,加赛中的前2%将进入下一轮。

    欢迎您收看有洛谷卫视重磅推出的综合性文艺知识类节目“开心玩游戏,轻松赢比赛”,我是LUWM。学编程,就选洛谷, 感谢洛谷Online Judge对本节目的大力支持。下面,我们有请10位选手上台,由大屏幕给出题目。

    题目描述

    话说埃菲尔铁塔小区的房子只有一栋,且只有一层,其中每一家都装有一个监听器,具体地,如果编号为第i家的人给编号第j家的人打了电话,i<=j,当然,也会有些人无聊地自己给自己打电话,那么第i,i+1,i+2,…,j-1,j号的监听器都会收到一次信号。现在把每个监听器的收到信号数都告诉你(即A1到An),请问他们至少打了几次电话?

    输入输出格式

    输入格式:

    第一行一个数N,表示用户数。

    第二行N个数,表示监听器收到的信号数。

    输出格式:

    一个数,最少的打电话次数。

    输入输出样例

    输入样例#1:

    5
    1 2 3 2 1
    

    输出样例#1:

    3
    

    输入样例#2:

    5
    1 4 4 5 1
    

    输出样例#2:

    5
    

    说明

    对于100%的数据,1<=N<=1000,1<=Ai<=2000

    思路:跟上一道题一样……

    代码:

    #include<cstdio>
    #include<cctype>
    #define maxn 100007
    #define ll long long
    using namespace std;
    int n,a[maxn],ans;
    inline int qread() {
    	char c=getchar();int num=0,f=1;
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) num=num*10+c-'0';
    	return num*f;
    }
    int main() {
    	n=qread();
    	for(int i=1;i<=n;++i) {
    		a[i]=qread();
    		if(a[i]>a[i-1]) ans+=a[i]-a[i-1];
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    5. 洛谷P2486 [SDOI2011]染色

    题目描述

    输入输出格式

    输入格式:

    输出格式:

    对于每个询问操作,输出一行答案。

    输入输出样例

    输入样例#1:

    6 5
    2 2 1 2 1 1
    1 2
    1 3
    2 4
    2 5
    2 6
    Q 3 5
    C 2 1 1
    Q 3 5
    C 5 1 2
    Q 3 5
    

    输出样例#1:

    3
    1
    2
    

    说明

    思路:对于题目中的操作1,我们可以用树链剖分来实现,就是树链剖分的基本操作,难点就在于操作2,这个操作是要求求任意两点间的颜色段数量,单纯的用线段树维护区间和肯定是不行的,那么就考虑去重,去重机制是怎样的呢?就是我们记录一个lc表示一个区间的左端点颜色是什么,rc表示一个区间的右端点颜色是什么,但我们合并左右区间时,如果lc[rs]=rc[ls],那么这时候就会出现重复,ans就要-1。还有就是在进行树链剖分的时候,在不断往上跳的过程中也会出现类似的重复,具体实现看代码。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #include<iostream>
    #define maxn 100007
    #define ls rt<<1
    #define rs rt<<1|1
    using namespace std;
    int n,m,head[maxn],d[maxn],size[maxn],son[maxn],w[maxn];
    int cnt,num,top[maxn],sum[maxn<<2],lazy[maxn<<2];
    int lc[maxn<<2],rc[maxn<<2],fa[maxn],id[maxn],a[maxn];
    char s;
    inline int qread() {
      char c=getchar();int num=0,f=1;
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) num=num*10+c-'0';
      return num*f;
    }
    struct node {
      int v,nxt;
    }e[maxn<<1];
    inline void ct(int u, int v) {
      e[++num].v=v;
      e[num].nxt=head[u];
      head[u]=num;
    }
    void dfs1(int u, int f) {
      size[u]=1;
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v!=f) {
          d[v]=d[u]+1;
          fa[v]=u;
          dfs1(v,u);
          size[u]+=size[v];
          if(size[v]>size[son[u]]) son[u]=v;
        }
      }
    }
    void dfs2(int u, int t) {
      id[u]=++cnt;
      a[cnt]=w[u];
      top[u]=t;
      if(son[u]) dfs2(son[u],t);
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
      }
    }
    inline void pushup(int rt) {
      sum[rt]=sum[ls]+sum[rs]-(lc[rs]==rc[ls]);
      rc[rt]=rc[rs];
      lc[rt]=lc[ls];
    }
    void build(int rt, int l, int r) {
      if(l==r) {
        sum[rt]=1;
        lc[rt]=rc[rt]=a[l];
        return;
      }
      int mid=(l+r)>>1;
      build(ls,l,mid);
      build(rs,mid+1,r);
      pushup(rt);
    }
    inline void pushdown(int rt) {
      if(lazy[rt]) {
        sum[ls]=sum[rs]=1;
        lazy[ls]=lazy[rs]=lc[ls]=lc[rs]=rc[ls]=rc[rs]=lazy[rt];
        lazy[rt]=0;
      }
    }
    void modify(int rt, int l, int r, int L, int R, int val) {
      if(L>r||R<l) return;
      if(L<=l&&r<=R) {
        sum[rt]=1;
        lc[rt]=rc[rt]=lazy[rt]=val;
        return;
      }
      pushdown(rt);
      int mid=(l+r)>>1;
      if(L<=mid) modify(ls,l,mid,L,R,val);
      if(R>mid) modify(rs,mid+1,r,L,R,val);
      pushup(rt);
    }
    int csum(int rt, int l, int r, int L, int R) {
      if(L>r||R<l) return 0;
      if(L<=l&&r<=R) return sum[rt];
      pushdown(rt);
      int mid=(l+r)>>1;
      int ans=0,js=0;
      if(L<=mid) ans+=csum(ls,l,mid,L,R),js++;
      if(R>mid) ans+=csum(rs,mid+1,r,L,R),js++;
      if(js==2) ans-=(rc[ls]==lc[rs]);
      return ans;
    } 
    int cx(int rt, int l, int r, int L) {
      if(l==r) return lc[rt];
      int mid=(l+r)>>1;
      pushdown(rt);
      if(L<=mid) return cx(ls,l,mid,L);
      else return cx(rs,mid+1,r,L);
    }
    void cal(int x, int y, int val) {
      int fx=top[x],fy=top[y];
      while(fx!=fy) {
        if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
        modify(1,1,cnt,id[fx],id[x],val);
        x=fa[fx],fx=top[x];
      }
      if(id[x]>id[y]) swap(x,y);
      modify(1,1,cnt,id[x],id[y],val);
    }
    int query(int x, int y) {
      int fx=top[x],fy=top[y],ans=0;
      int ans1=0,ans2=0;
      while(fx!=fy) {
        if(d[fx]<d[fy]) swap(x,y),swap(fx,fy),swap(ans1,ans2);
        ans+=csum(1,1,cnt,id[fx],id[x]);
        ans-=(cx(1,1,cnt,id[x])==ans1);
        ans1=cx(1,1,cnt,id[fx]);
        x=fa[fx],fx=top[x];
      }
      if(id[x]>id[y]) swap(x,y),swap(ans1,ans2);
      ans+=csum(1,1,cnt,id[x],id[y]);
      if(cx(1,1,cnt,id[x])==ans1) --ans;
      if(cx(1,1,cnt,id[y])==ans2) --ans;
      return ans;
    }
    int main() {
      n=qread(),m=qread();
      for(int i=1;i<=n;++i) w[i]=qread();
      for(int i=1,u,v;i<n;++i) {
        u=qread(),v=qread();
        ct(u,v);ct(v,u);
      }
      d[1]=1;dfs1(1,0);dfs2(1,1);build(1,1,n);
      for(int i=1,x,y,c;i<=m;++i) {
        cin>>s;x=qread(),y=qread();
        if(s=='C') {
          c=qread();
          cal(x,y,c);
        }
        else printf("%d
    ",query(x,y));
      }
      return 0;
    }
    

    6. 洛谷P3979 遥远的国度

    题目描述

    zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

    问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。

    RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。

    由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

    输入输出格式

    输入格式:

    第1行两个整数n m,代表城市个数和操作数。

    第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。

    第n+1行,有n个整数,代表所有点的初始防御值。

    第n+2行一个整数 id,代表初始的首都为id。

    第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

    输出格式:

    对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

    输入输出样例

    输入样例#1:

    3 7
    1 2
    1 3
    1 2 3
    1
    3 1
    2 1 1 6
    3 1
    2 2 2 5
    3 1
    2 3 3 4
    3 1
    

    输出`样例#1:

    1
    2
    3
    4
    

    说明

    对于20%的数据,n<=1000 m<=1000。

    对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。

    对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。

    对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。

    对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

    思路:首先,第二和第三个操作都是树链剖分的基本操作,然后,这个题的难点在换根上,当然,可以用LCT实现……然而,我不会,所以就只能换一种思路,首先,换一次顶点dfs一次,建树一次,肯定会超时。那么我们来看,一个点成为根结点之后,只会影响到这个点到原来根结点那条路径上的点,所以,当查询一个点,跟当前点的LCA在这条链上时,我们就可以脑补一下,查询区间就是当前根到原根的路径上的原根的第一个儿子的子树的补集,然后剩余的两种情况,LCA是原根或当前根等于原根,直接modify即可。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #define maxn 100007
    #define ls rt<<1
    #define rs rt<<1|1
    using namespace std;
    int n,m,head[maxn],son[maxn],size[maxn],d[maxn];
    int cnt,num,top[maxn],minn[maxn<<2],id[maxn],fa[maxn];
    int w[maxn],a[maxn],rt,lazy[maxn<<2];
    inline int qread() {
      char c=getchar();int num=0,f=1;
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) num=num*10+c-'0';
      return num*f;
    }
    struct node {
      int v,nxt;
    }e[maxn<<1];
    inline void ct(int u, int v) {
      e[++num].v=v;
      e[num].nxt=head[u];
      head[u]=num;
    }
    inline void pushup(int rt) {
      minn[rt]=min(minn[ls],minn[rs]);
    }
    void build(int rt, int l, int r) {
      if(l==r) {
        minn[rt]=a[l];
        return;
      }
      int mid=(l+r)>>1;
      build(ls,l,mid);
      build(rs,mid+1,r);
      pushup(rt);
    }
    inline void pushdown(int rt) {
      if(lazy[rt]) {
          minn[ls]=lazy[ls]=minn[rs]=lazy[rs]=lazy[rt];
          lazy[rt]=0;
      }
    }
    void modify(int rt, int l, int r, int L, int R, int val) {
      if(L>r||R<l) return;
      if(L<=l&&r<=R) {
        minn[rt]=val;
        lazy[rt]=val;
        return;
      }
      pushdown(rt);
      int mid=(l+r)>>1;
      modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val);
      pushup(rt);
    }
    int cmin(int rt, int l, int r, int L, int R) {
      if(L>r||R<l) return 0x7fffffff;
      if(L<=l&&r<=R) return minn[rt];
      int mid=(l+r)>>1;
      int minn=0x7fffffff;
      pushdown(rt);
      if(L<=mid) minn=min(minn,cmin(ls,l,mid,L,R));
      if(R>mid) minn=min(minn,cmin(rs,mid+1,r,L,R));
      return minn;
    }
    void dfs1(int u, int f) {
      size[u]=1;
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v!=f) {
          d[v]=d[u]+1;
          fa[v]=u;
          dfs1(v,u);
          size[u]+=size[v];
          if(size[v]>size[son[u]]) son[u]=v;
        }
      }
    }
    void dfs2(int u, int t) {
      id[u]=++cnt;
      a[cnt]=w[u];
      top[u]=t;
      if(son[u]) dfs2(son[u],t);
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
      }
    }
    inline int lca(int x, int y) {
      int fx=top[x],fy=top[y];
      while(fx!=fy) {
        if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
        x=fa[fx],fx=top[x];
      }
      return d[x]>d[y]?y:x;
    }
    void cal(int x, int y, int val) {
      int fx=top[x],fy=top[y];
      while(fx!=fy) {
        if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
        modify(1,1,cnt,id[fx],id[x],val);
        x=fa[fx],fx=top[x];
      }
      if(id[x]>id[y]) swap(x,y);
      modify(1,1,cnt,id[x],id[y],val);
    }
    int main() {
      n=qread(),m=qread();
      for(int i=1,u,v;i<n;++i) {
        u=qread(),v=qread();
        ct(u,v);ct(v,u);
      }
      for(int i=1;i<=n;++i) w[i]=qread();
      rt=qread();
      dfs1(1,0);dfs2(1,1);build(1,1,n);
      for(int i=1,k,x,y,w;i<=m;++i) {
        k=qread();
        if(k==1) x=qread(),rt=x;
        if(k==2) x=qread(),y=qread(),w=qread(),cal(x,y,w);
        if(k==3) {
          x=qread();
          if(x==rt) {
            printf("%d
    ",minn[1]);
            continue;
          }
          int lc=lca(x,rt);
          if(lc!=x) {
            printf("%d
    ",cmin(1,1,n,id[x],id[x]+size[x]-1));
            continue;
          }
          if(lc==x) {
            int s;
            for(int i=head[x];i;i=e[i].nxt) {
              int v=e[i].v;
              if(id[v]<=id[rt]&&id[v]+size[v]-1>=id[rt]) {
                s=v;
                break;
              }
            }
            printf("%d
    ",min(cmin(1,1,n,1,id[s]-1),cmin(1,1,n,id[s]+size[s],n)));
          }
        }
      }
      return 0;
    }
    

    7. CF616D Longest k-Good Segment

    题目描述

    The array aa with nn integers is given. Let's call the sequence of one or more consecutive elements in aa segment. Also let's call the segment k-good if it contains no more than kk different values.

    Find any longest k-good segment.

    As the input/output can reach huge size it is recommended to use fast input/output methods: for example, prefer to use scanf/printf instead of cin/cout in C++, prefer to use BufferedReader/PrintWriter instead of Scanner/System.out in Java.

    输入输出格式

    输入格式:

    The first line contains two integers n,kn,k ( 1<=k<=n<=5·10^{5}1<=k<=n<=5⋅105 ) — the number of elements in aa and the parameter kk .

    The second line contains nn integers a_{i}ai​ ( 0<=a_{i}<=10^{6}0<=ai​<=106 ) — the elements of the array aa .

    输出格式:

    Print two integers l,rl,r ( 1<=l<=r<=n1<=l<=r<=n ) — the index of the left and the index of the right ends of some k-good longest segment. If there are several longest segments you can print any of them. The elements in aa are numbered from 11 to nn from left to right.

    输入输出样例

    输入样例#1:

    5 5
    1 2 3 4 5
    

    输出样例#1:

    1 5
    

    输入样例#2:

    9 3
    6 5 1 2 3 2 1 4 5
    

    输出样例#2:

    3 7
    

    输入样例#3:

    3 1
    1 2 3
    

    输出样例#3:

    1 1
    

    思路:题意为在长度为n的串中找出有k个不同数字的最长连续子串,输出子串开始以及结束的位置,然而数据有点水,我们直接用STL中的map记录一下即可。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<map>
    #define maxn 1000007
    using namespace std;
    map <int,int> mp;
    int a[maxn],l,len,cyh,zrj;
    void del(int x)
    {
        mp[x]--;
        if(mp[x]==0) mp.erase(x);
    }
    int main() {
      int n,k;
      scanf("%d%d",&n,&k);
      for(int i=0;i<n;++i) scanf("%d",&a[i]);
      for(int i=0;i<n;++i) {
        mp[a[i]]++;
        if(mp.size()>k) {
          for(;l<n&&mp.size()>k;++l)
            del(a[l]);
        }
        int ll=i-l+1;
        if(ll>len) {
          len=ll;
          cyh=l;
          zrj=i;
        }
      }
      printf("%d %d
    ",cyh+1,zrj+1);
      return 0;
    }
    

    8. 洛谷P2253 好一个一中腰鼓!

    题目背景

    话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来。

    Ivan乱入:“忽一人大呼:‘好一个安塞腰鼓!’满座寂然,无敢哗者,遂与外人间隔。”

    题目描述

    设想一下,腰鼓有两面,一面是红色的,一面是白色的。初二的苏大学神想给你这个oier出一道题。假设一共有N(1<=N<=20,000)个同学表演,表演刚开始每一个鼓都是红色面朝向观众,舞蹈老师会发出M(1<=M<=20,000)个指令,如果指令发给第i个表演的同学,这位同学就会把腰鼓反过来,如果腰鼓之前是红色面朝向观众的,那么就会变成白色面朝向观众,反之亦然。那么问题来了(!?),在老师每一次发出指令后,找到最长的连续的一排同学,满足每相邻的两个手中的腰鼓朝向观众的一面互不相同,输出这样一排连续的同学的人数。

    输入输出格式

    输入格式:

    第一行有两个整数, 分别为表演的同学总数N, 和指令总数M。

    之后M行, 每行有一个整数i: 1<=i<=N, 表示舞蹈老师发出的指令。

    输出格式:

    输出有M行, 其中每i行有一个整数.

    表示老师的第i条指令发出之后, 可以找到的满足要求的最长连续的一排表演同学有多长?

    输入输出样例

    输入样例#1:

    6 2
    2
    4
    

    输出样例#1:

    3
    5
    

    说明

    Huangc温馨提示:其实数据根本没你想象的那么大。。。[坏笑]、、

    思路:首先对于修改操作显然我们可以用线段树的单点修改来维护,然后对于查询操作,可以用一种类似于求区间最大字段和的思想,但是需要记录一个lc和rc,分别表示一个区间左端点和右端点的状态是什么,pushup的时候判断一下即可。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #define maxn 20007
    #define ls rt<<1
    #define rs rt<<1|1
    using namespace std;
    int n,m,lmax[maxn<<2],maxx[maxn<<2],rmax[maxn<<2],lc[maxn<<2],rc[maxn<<2];
    inline int qread() {
      char c=getchar();int num=0,f=1;
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) num=num*10+c-'0';
      return num*f;
    }
    void build(int rt, int l, int r) {
      lmax[rt]=rmax[rt]=maxx[rt]=1;
      if(l==r) return;
      int mid=(l+r)>>1;
      build(ls,l,mid);
      build(rs,mid+1,r);
    }
    inline void pushup(int rt, int len) {
      if(lmax[ls]==(len-(len>>1))&&lc[rs]!=rc[ls]) 
        lmax[rt]=(len-(len>>1))+lmax[rs];
      else lmax[rt]=lmax[ls];
      if(rmax[rs]==(len>>1)&&lc[rs]!=rc[ls])
        rmax[rt]=(len>>1)+rmax[ls];
      else rmax[rt]=rmax[rs];
      maxx[rt]=max(maxx[ls],maxx[rs]);
      if(rc[ls]!=lc[rs]) maxx[rt]=max(maxx[rt],lmax[rs]+rmax[ls]);
      lc[rt]=lc[ls],rc[rt]=rc[rs];
    }
    void add(int rt, int l, int r, int L) {
      if(l==r) {
      	lc[rt]^=1;
    	rc[rt]^=1;
    	return;	
      }
      int mid=(l+r)>>1;
      if(L<=mid) add(ls,l,mid,L);
      else add(rs,mid+1,r,L);
      pushup(rt,r-l+1);
    }
    int main() {
      n=qread(),m=qread();
      build(1,1,n);
      for(int i=1,x;i<=m;++i) {
      	x=qread();
      	add(1,1,n,x);
      	printf("%d
    ",maxx[1]);
      }
      return 0;
    }
    
  • 相关阅读:
    OpenCV 3-1.1-头文件
    安装ROS报错:The following packages have unmet dependenctes:
    机器人学——3.3-逆运动学
    机器人学——3.2-正运动学
    机器人学——3.1-机械臂DH参数
    机器人学——2.4-坐标系的旋转和运动增量
    机器人学——2.3-姿态插值和笛卡尔运动
    面向对象
    数组
    变量总结
  • 原文地址:https://www.cnblogs.com/grcyh/p/10193072.html
Copyright © 2011-2022 走看看