{{{ #!cplusplus /* ymc 2009/4/8 线段树 zju 1610 题目大意: 在x轴上,每次在某一个区间画一种颜色,求最后每种颜色的 选段要多少条。 l[i],r[i],c[i]表示在区间[l[i],r[i]]上画颜色c[i] (颜色保存的时候保存c[i]+1,因为会出现0号颜色,但是 线段树中用0表示背景色) 用Left,Right记录最左边的左边和最右边的坐标 用Left_c,Right_c记录最小的颜色和最大的颜色 flag[i]记录第i号颜色的线段数。 */ #include #include using namespace std; const int N=20000; int tree[N]; int l[N],r[N],c[N]; int flag[N]; int n; int Left,Right,Left_c,Right_c;; void Init() { Left=INT_MAX; Right=INT_MIN; Left_c=INT_MAX; Right_c=INT_MIN; for(int i=0;iRight) Right=r[i]; c[i]++; if(c[i]Right_c) Right_c=c[i]; } for(int k=1;k<=2*(Right-Left);k++) tree[k]=0;//0为初始颜色即背景颜色 for(int k=Left_c;k<=Right_c;k++) flag[k]=0;//所有颜色的线段数初始为0 } /* 在以tree[k]为树根的线段树(代表的区间为[l,r])上 在区间[a,b]颜色c */ void Insert(int k,int l,int r,int a,int b,int c) { if(tree[k]==c)//已经有的颜色要要画的颜色相同 return; if(l==a&&r==b)//正好画满整个线段树 { tree[k]=c; return; } if(tree[k]>=0)//[l,r]上已有一种颜色,则上色后有多种颜色 { tree[2*k]=tree[k]; tree[2*k+1]=tree[k]; tree[k]=-1;//-1表示该区间有多种颜色 } int m=(l+r)/2; if(b<=m)//左儿子上色 Insert(2*k,l,m,a,b,c); else if(m<=a)//右儿子上色 Insert(2*k+1,m,r,a,b,c); else//左右儿子均上色 { Insert(2*k,l,m,a,m,c); Insert(2*k+1,m,r,m,b,c); } } /* 在以tree[k]为树根的线段树[l,r]上统计不同颜色的线段数 lc,rc为[l,r]上左右端点的颜色 */ void Count(int k,int l,int r,int &lc,int &rc) { if(tree[k]>=0)//[l,r]上颜色单一 { lc=tree[k];//父节点需要知道 rc=tree[k]; flag[tree[k]]++; return ; } if(l>=r) return; int tl,tr; Count(2*k,l,(l+r)/2,lc,tl);//统计左儿子 Count(2*k+1,(l+r)/2,r,tr,rc);//统计右儿子 if(tl==tr)//左儿子的最右线段与右儿子的最左线段同色 flag[tl]--; } void Solve() { for(int i=0;i0) printf("%d %d\n",k-1,flag[k]); } int main() { while(scanf("%d",&n)!=EOF) { Init(); Solve(); OutPut(); printf("\n"); } } }}} {{{ #!cplusplus /* 1610 Count the Colors ymc */ #include using namespace std; const int N=8010; struct Point { int e; int s; }; Point a[N]; int b[N]; int n; int main() { int c,d,color; while( scanf("%d",&n)!=EOF ) { for(int i=0;i=N) break; b[a[i].s]++; i=k; } for(int i=0;i0) printf("%d %d\n",i,b[i]); printf("\n"); } } }}}