5.26小测

1.2039. 树的统计

★★   输入文件:counttree.in   输出文件:counttree.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

关于树的统计问题有多种多样的版本,这里你需要解决一个比较简单的问题:对于一棵包含N个节点的有根树,将所有点从1到N编号后,对于每一个节点v,统计出以v为根的子树中有多少个点的编号比v小。

【输入格式】

输入第一行包含一个整数N,以下N行每行包含一个整数,其中第i行的整数表示编号为i的节点的父亲节点的编号,根的父亲节点编号为0。

【输出格式】

输出包含N行,其中第i行给出编号为i的节点的统计结果。

【样例输入】

3
2
3
0

【样例输出】

0 1 2

【提示】

在此键入。

【来源】

20%的数据1<=n<=1000

100%的数据1<=n<=100000

思路:

  三个题,(老师特意提醒题目先后顺序与题目难度无关),一看题目这个题“太难了”,我不会啊,跳过……

  于是乎,偶最后做的这个题,由于偶坚定不移的相信,这个题我不会啊,立马打了个暴力,又一看数据范围,100000???

  so,我有更坚定了我做不出来的想法,可是没想到啊,我竟然A了,什么情况!!!

 来来来~~ 说正题,暴力非常简单,输入建边,然后询问的时候,题目要求第i行给出编号为i的节点的统计结果,所以dfs(i),从当前节点一直往它指向的点搜索,如果小于,ans就+1,输出答案,似不似很简单的暴力啊~~

Y^o^Y  代码:

#include<iostream>
#include<cstdio>
using namespace std;

const int N = 100002;
int n,head[N],num_edge,v,ans,tmp;
struct Edge{
    int pre,v,u;
}edge[N*4];

void add_edge(int u,int v) {
    edge[++num_edge].pre = head[u];
    edge[num_edge].v = v;
    edge[num_edge].u = u;
    head[u] = num_edge;
}

int dfs(int k) {
    for(int i=head[k]; i; i=edge[i].pre) {
        if(edge[i].v<tmp) 
            ans++;
        dfs(edge[i].v);
    }
    return ans;
}

int main() {
    //freopen("counttree.in","r",stdin);
    //freopen("counttree.out","w",stdout);
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d",&v);
        add_edge(v,i);
    }
    for(int p=1; p<=n; p++) {
        ans=0;
        tmp=p;
        printf("%d\n",dfs(p));
    }
    return 0;
}

2.1682. [HAOI2014]贴海报

★★☆   输入文件:ha14d.in   输出文件:ha14d.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

Bytetown城市要进行市长竞选,所有的选民可以畅所欲言地对竞选市长的候选人发表言论。为了统一管理,城市委员会为选民准备了一个张贴海报的electoral墙。

张贴规则如下:

1.electoral墙是一个长度为N个单位的长方形,每个单位记为一个格子;

2.所有张贴的海报的高度必须与electoral墙的高度一致的;

3.每张海报以“A B”表示,即从第A个格子到第B个格子张贴海报;

4.后贴的海报可以覆盖前面已贴的海报或部分海报。

现在请你判断,张贴完所有海报后,在electoral墙上还可以看见多少张海报。

【输入格式】

第一行:     N   M            分别表示electoral墙的长度和海报个数

接下来M行:   Ai   Bi          表示每张海报张贴的位置

【输出格式】

输出贴完所有海报后,在electoral墙上还可以看见的海报数。

【样例输入】

100 5

1 4

2 6

8 10

3 4

7 10

【样例输出】

4

【提示】

【约束条件】

1 0<= N <= 10000000     1<=M<=1000   1<= Ai <= Bi <=10000000

所有的数据都是整数。数据之间有一个空格

【来源】

在此键入。

T^T 代码:

1. 47分代码——暴力算法

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m,a,b,newspaper[10000003];
int k,ll=0x7fffffff,rr,ans;

int main() {
    freopen("ha14d.in","r",stdin);
    freopen("ha14d.out","w",stdout);
    scanf("%d%d",&n,&m);
    memset(newspaper,0,sizeof(newspaper));
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&a,&b);
        ll=min(ll,a);
        rr=max(rr,b);
        ++k;
        for(int i=a; i<=b; i++)
            newspaper[i]=k;    
    }
    sort(newspaper+ll,newspaper+rr+1);
    ans=1;
    for(int i=ll; i<rr; i++) {
        if(newspaper[i]!=newspaper[i+1]) {
            ans++;
        }
    }
    printf("%d",ans);
    return 0;
}

 

2.AC代码

 

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int oo=987654321;
const int maxn=1005;
int cnt=0,total,ans=0,dif,n,m;
int edge[maxn];
struct edgee {
    int leftt,rightt;
    int cut;
} e[maxn];
struct ppp {
    int id;
    bool flag;
} p[maxn<<1],stt,endd;
bool mycmp(ppp a,ppp b) {
    return ((a.id<b.id) || (a.id==b.id && a.flag<b.flag));
}
void dydxh() {
    sort(p+1,p+1+(m<<1),mycmp);
    for(int j=2; j<=cnt; j++) {
        if(p[j-1].id+p[j-1].flag==p[j].id+p[j].flag)  //如果是同一个点,就排除掉;
            continue;
        stt.id=p[j-1].id,stt.flag=p[j-1].flag;
        endd.id=p[j].id,endd.flag=p[j].flag;
        total=0;
        for(int i=1; i<=m; i++)
            if(e[i].leftt<=(stt.id+stt.flag) && (endd.id+endd.flag-1)<=e[i].rightt)
                edge[++total]=i;
        for(int i=1; i<total; i++)
            e[edge[i]].cut+=(endd.id+endd.flag-stt.id-stt.flag);
    }
}
int main() {
    //freopen("ha14d.in","r",stdin);
    //freopen("ha14d.out","w",stdout);
    scanf("%d%d",&n,&m);
    ans=m;
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&e[i].leftt,&e[i].rightt);
        p[++cnt].id=e[i].leftt,p[cnt].flag=0;
        p[++cnt].id=e[i].rightt,p[cnt].flag=1;
    }
    dydxh();
    for(int i=1; i<=m; i++) {
        if(e[i].cut==(e[i].rightt-e[i].leftt+1))
            ans--;
    }
    printf("%d\n",ans);
    return 0;
}

 

1619. [HEOI2012]采花

★★☆   输入文件:1flower.in   输出文件:1flower.out   简单对比
时间限制:5 s   内存限制:128 MB

【题目描述】

萧薰儿是古国的公主,平时的一大爱好是采花。
今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一排的,以便于公主采花。公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了m个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答案!),最后会选择令公主最高兴的行程(为了拿到更多奖金!)。

【输入格式】

 第一行四个空格隔开的整数n、c以及m。接下来一行n个空格隔开的整数,每个数在[1, c]间,第i个数表示第i朵花的颜色。接下来m行每行两个空格隔开的整数l和r(l ≤ r),表示女仆安排的行程为公主经过第l到第r朵花进行采花。

【输出格式】

共m行,每行一个整数,第i个数表示公主在女仆的第i个行程中能采到的花的颜色数。

【样例输入】

5  3 5
  1  2 2 3 1
  1  5
  1  2
  2  2
  2  3
  3  5

【样例输出】

2 
  0 0 1 0 
  【样例说明】
  询问[1, 5]:公主采颜色为1和2的花,由于颜色3的花只有一朵,公主不采;询问[1, 2]:颜色1和颜色2的花均只有一朵,公主不采;
  询问[2, 2]:颜色2的花只有一朵,公主不采;
  询问[2, 3]:由于颜色2的花有两朵,公主采颜色2的花;
  询问[3, 5]:颜色1、2、3的花各一朵,公主不采。

【提示】

【数据范围】

对于100%的数据,1 ≤ n ≤    10^6,c ≤ n,m ≤10^6。

【来源】

【题目来源】

耒阳大世界(衡阳八中) OJ 2743

思路:

定义next[i]为第i个位置的下一个和它相同颜色的位置。这里我把没有下一个的next[i]定为了n+1

例如 :1 2 2 3 1

next[] 5 3 6 6 6

然后O(n)扫一遍数组,把每种颜色第二次出现的位置在树状数组中记录下来。

上面的例子中就把 位置3和位置5 所在的位置+1  。用树状数组维护一下就好了。

对于每组询问(l,r)我们要求的是从l开始到r中的第二次出现的数。

然后把所有询问按左端点排个序。(因为排完序后就是单调的啦)

然后对于每个询问,在树状数组中把(l,r)中第二次出现的数在树状数组中取出个数。(树状数组中本身存储的就是第二次出现的数的个数)

然后左端点要递增的话,把左端点位置上的数的next[i]在树状数组-1,把next[next[i]]在树状数组中+1,也就是继续维护第二次出现的数。然后把左端点向右移动到当前询问的左端点。

然后就好了。离线处理大法好!!!

 

T^T 代码:

1. 20分代码——暴力算法

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N = 1000003;
int n,c,m,l,r;
int hua[N],num[N];

void ask(int l,int r) {
    int ans=0;
    memset(num,0,sizeof(num));
    for(int i=l; i<=r; i++) {
        num[hua[i]]++;
    }
    for(int i=1; i<=c; i++) {
        if(num[i]>1) 
        ans++;
    } 
    printf("%d\n",ans);
}

int main() {
    freopen("1flower.in","r",stdin);
    freopen("1flower.out","w",stdout);
    scanf("%d%d%d",&n,&c,&m);
    for(int i=1; i<=n; i++) 
        scanf("%d",&hua[i]);
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&l,&r);
        ask(l,r);
    }
    return 0;
}

2.AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 1000010
struct node {
    int l,r,id;
} q[MAXN];
int a[MAXN],gs[MAXN],BIT[MAXN],ans[MAXN],next[MAXN],last[MAXN],n;
int read() {
    int s=0,fh=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {
        if(ch=='-')fh=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        s=s*10+(ch-'0');
        ch=getchar();
    }
    return s*fh;
}
int Lowbit(int k) {
    return k&(-k);
}
void Update(int k,int k1) {
    while(k<=n) {
        BIT[k]+=k1;
        k+=Lowbit(k);
    }
}
int Sum(int k) {
    int sum=0;
    while(k>0) {
        sum+=BIT[k];
        k-=Lowbit(k);
    }
    return sum;
}
bool cmp(node aa,node bb) {
    return aa.l<bb.l;
}
int main() {
    //freopen("1flower.in","r",stdin);
    //freopen("1flower.out","w",stdout);
    int c,m,i,L;
    n=read();
    c=read();
    m=read();
    for(i=1; i<=n; i++)a[i]=read();
    for(i=1; i<=m; i++)q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    for(i=1; i<=n; i++) {
        if(last[a[i]]!=0)next[last[a[i]]]=i;
        last[a[i]]=i;
    }
    for(i=1; i<=n; i++) {
        gs[a[i]]++;
        if(gs[a[i]]==2)Update(i,1);
    }
    L=1;
    for(i=1; i<=m; i++) {
        while(L<q[i].l) {
            if(next[L]!=0)Update(next[L],-1);
            if(next[next[L]]!=0)Update(next[next[L]],1);
            L++;
        }
        ans[q[i].id]=Sum(q[i].r)-Sum(q[i].l-1);
    }
    for(i=1; i<=m; i++)printf("%d\n",ans[i]);
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

 

自己选的路,跪着也要走完!!!

posted @ 2017-07-12 10:06  橘生淮南终洛枳  阅读(180)  评论(0编辑  收藏  举报