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
【题目描述】
【输入格式】
【输出格式】
【样例输入】
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。
【来源】
【题目来源】
思路:
定义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; }
自己选的路,跪着也要走完!!!