/*树状数组这道题的操作有三种,插入和删除并到一个函数里完成 ,查询的操作要用到二分的方法。*/#include <cstdio>#include <string.h>#include <stdlib.h>#include <algorithm>using namespace std;const int M = 100005;int num[M];int lowbit( int x ){ return x&(-x); }void add( int x , int val ){ while( x < M ) { num[x] += val; x += lowbit(x); }}int sum( int x ){ int ret = 0; while( x > 0 ) { ret += num[x]; x -= lowbit(x); } return ret;}int find( int pos , int k ){ int neww = sum(pos); int l , r , m; l = pos + 1; r = M - 1; int ans = M; int total = 0; while( l <= r ) { m = ( l+r ) / 2; total = sum(m) - neww; if( total >= k ) { r = m - 1; if( m < ans ) ans = m; } else l = m + 1; } return ans;}int main( ){ int n; int c,x,y; while( scanf("%d",&n) != EOF ) { memset( num , 0 , sizeof(num) ); while( n-- ){ scanf("%d",&c); if( c == 0 ){ scanf("%d",&x); add( x , 1 ); } else if( c == 1 ){ scanf("%d",&x); if( sum(x) - sum(x-1) == 0 ) printf("No Elment!\n"); else add( x , -1 ); } else if( c == 2 ){ scanf("%d%d",&x,&y); int ret = find( x , y ); if( ret == M ) printf("Not Find!\n"); else printf("%d\n",ret); } } } return 0;}
敌兵布阵
#include<cstdio>#include<iostream>using namespace std;#define maxn 50005int tree[maxn<<2];void build(int left,int right,int root){ if (left == right) { scanf("%d",&tree[root]); return ; } int mid = (left + right) >> 1; build(left , mid , root << 1); build(mid + 1 , right , root << 1 | 1); tree[root]=tree[root<<1]+tree[root<<1|1];}int find(int from,int to,int left,int right,int root){ if(from<=left&&right<=to) { return tree[root]; } int mid=(left+right)>>1; int sum=0; if(from<=mid)sum+=find(from,to,left,mid,root<<1); if(to>mid)sum+=find(from,to,mid+1,right,root<<1|1); return sum;}void update(int p,int add,int left,int right,int root){ if(left==right) { tree[root]+=add; return ; } int mid=(left+right)>>1; if(p<=mid)update(p,add,left,mid,root<<1); else update(p,add,mid+1,right,root<<1|1); tree[root]=tree[root<<1]+tree[root<<1|1];}int main(){ //freopen("in.txt","r",stdin); int cas; char s[10]; scanf("%d",&cas); for(int i=1;i<=cas;i++) { int n; printf("Case %d:\n",i); scanf("%d",&n); build(1,n,1); while(scanf("%s",s)) { int x,y; if(s[0]=='E')break; scanf("%d%d",&x,&y); if(s[0]=='A')update(x,y,1,n,1); else if(s[0]=='Q')printf("%d\n",find(x,y,1,n,1)); else update(x,-y,1,n,1); } } return 0;}
Median Filter
/*我们按“S”型枚举每一个点,如左图:即右->下->左->下->右....用一个集合存储当前子正方形内的数,下一次查找时,插入新的一列,删除旧的列。如右图:当前枚举点150(三角标记),黑色正方形的值保存一个集合中,求出中位数。当枚举的点有150移动到125时,我们把蓝色椭圆内的点插入,把黄色椭圆内的点删掉,此时集合中的元素即为红色正方形内的元素,可求出新的中位数。不断如此操作,直到结束。首先分析一下复杂度:子正方形边长L=2*r+1,N=L*L枚举每个点,需要(500-L)* (500-L) 下面主要的问题是如何快速求中位数? 如果每次排序找中位数,需要Nlog(N),复杂度为:(500-L)* (500-L)* Nlog(N), 9<=N<250000,这么大的复杂度会超时。所以我们在查中位数时尽量降低复杂度。 树状数组和线段树都可以实现查找第k大数。线段树插入、查找均为log(N), 树状数组取决于二进制中1的个数,所以实际比log(N)还要快。 若用线段树,每次O(L*lgN)的插入,O(L*lgN)的删除,O(lgN)的查找。但写完后超时, 好像线段树系数很大,实现的时候不能完全达到log 用树状数组,每次O(L *lgN)的插入,O(L*lgN)的删除,O((lgN)^2)的查找, C++1.5秒可过。在查找时如果不用二分查找,也可优化为O(lgN)的查找,效率会更高。 */ #include <iostream>#include <cstdio>#include <cstring>using namespace std;int rr, c[1111111];int lowbit(int x){ return x & (-x);}void add(int i, int val){ while(i <= rr){ c[i] += val; i += lowbit(i); }}int sum(int i){ int s = 0; while(i > 0){ s += c[i]; i -= lowbit(i); } return s;}int mat[555][555];int ans[555][555];int mm;int Bin(){ int l = 1, r = rr; while(l < r){ int m = (l + r) >> 1; if(sum(m) >= mm) r = m; else l = m + 1; } return l - 1;}int main(){ //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); int n, r; while(scanf("%d %d", &n, &r) == 2){ if(!n && !r) { break; } r = (r << 1) + 1; mm = (r * r + 1) >> 1; rr = -1; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++){ scanf("%d", &mat[i][j]); rr = max(rr, mat[i][j] + 1); } memset(c, 0, sizeof(c)); for(int i = 0; i < r; i++){ for(int j = 0; j < r - 1; j++){ add(mat[i][j] + 1, 1); } } for(int i = 0; ; ){ for(int j = r - 1; j < n; j++){ for(int k = 0; k < r; k++) add(mat[i + k][j] + 1, 1); ans[i][j - (r - 1)] = Bin(); for(int k = 0; k < r; k++) add(mat[i + k][j - (r - 1)] + 1, -1); } for(int j = n - 1; j >= n - (r - 1); j--) add(mat[i][j] + 1, -1); i++; if(i + (r - 1) >= n) break; for(int j = n - 1; j >= n - (r - 1); j--) add(mat[i + (r - 1)][j] + 1, 1); for(int j = n - r; j >= 0; j--){ for(int k = 0; k < r; k++) add(mat[i + k][j] + 1, 1); ans[i][j] = Bin(); for(int k = 0; k < r; k++) add(mat[i + k][j + (r - 1)] + 1, -1); } for(int j = 0; j < (r - 1); j++) add(mat[i][j] + 1, -1); i++; if(i + (r - 1) >= n) break; for(int j = 0; j < (r - 1); j++) add(mat[i + (r - 1)][j] + 1, 1); } for(int i = 0; i <= n - r; i++){ for(int j = 0; j <= n - r; j++){ //if(j) printf(" "); printf("%d ", ans[i][j]); } printf("\n"); } } return 0;}
How far away ?
#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;#define MAX 40000struct edge{int v,w;};vector<edge> mp[MAX];vector<edge> query[MAX];bool flag[MAX];int pre[MAX],father[MAX],path[MAX];int find(int x){return x==pre[x]?x:pre[x]=find(pre[x]);}void LCA(int k){int i,j;for(i=0;i<mp[k].size();i++){int a=mp[k][i].v;if(!flag[a]){flag[a]=1;path[a]=path[k]+mp[k][i].w;LCA(a);pre[a]=k;for(j=0;j<query[a].size();j++){int b=query[a][j].v;if(flag[b]&&father[query[a][j].w]==-1){if(a==b)father[query[a][j].w]=0;elsefather[query[a][j].w]=path[a]+path[b]-2*path[find(b)];}}}}}int main(){int i,j,k,T,n,m,a,b;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(i=1;i<=n;i++){mp[i].clear();query[i].clear();flag[i]=0;father[i]=-1;pre[i]=i;path[i]=0;}int a,b,c;edge X;for(i=1;i<n;i++){scanf("%d%d%d",&a,&b,&c);X.v=b;X.w=c;mp[a].push_back(X);X.v=a;mp[b].push_back(X);}for(i=1;i<=m;i++){scanf("%d%d",&a,&b);X.v=b;X.w=i;query[a].push_back(X);X.v=a;query[b].push_back(X);}flag[1]=1;//path[1]=0;LCA(1);for(i=1;i<=m;i++)printf("%d\n",father[i]);}return 0;}
Connections between cities
/*这里要用到LCA,我们的距离为两个子节点到根的距离和减去最近祖先的距离的2倍;*/#include<cstdio>#include<iostream>#include<string.h>#include<vector>using namespace std;class node{public: int en; int len; };vector<node>tree[10024],Qes[10024];int dist[10024],set[10024],visit[10024],ans[1000024];void init( int n ){ for(int i=0;i<=n;i++) { dist[i]=0; set[i]=i; visit[i]=0;// indegree[i]=0; tree[i].clear( ); Qes[i].clear( ); } }inline int find( int x ){ return set[x]==x?x:set[x]=find( set[x] ); }inline void LCA( int num,int d,int root ){ dist[num]=d; set[num]=num; visit[num]=root;//标记为那棵树的根 int size=tree[num].size(); for( int i=0; i<size; i++ ) { if( !visit[tree[num][i].en] ) { LCA( tree[num][i].en,tree[num][i].len+d ,root); set[tree[num][i].en]=num; } } size=Qes[num].size( ); for( int i=0;i<size; i++ ) { if( visit[Qes[num][i].en] ) { if( visit[Qes[num][i].en]==root )//如果被标记过并且是同一棵树,就找最近祖先 { ans[Qes[num][i].len]=dist[num]+dist[Qes[num][i].en]-2*dist[find( Qes[num][i].en )]; } else ans[Qes[num][i].len]=-1;//要注意为-1,不能为0同点为0 } } }int main( ){ int n,m,Case,x,y,dis,N; while( scanf( "%d %d %d",&N,&n,&m )==3 ) { init( N ); for( int i=1; i<= n ;i++ ) { scanf( "%d %d %d",&x,&y,&dis ); node T; T.en = y; T.len = dis; tree[x].push_back( T );// indegree[y]++; T.en=x; tree[y].push_back( T ); } for( int i=1;i <= m ;i++ ) { scanf( "%d %d",&x,&y ); node T; T.en=y; T.len=i; // ans[i]=-1; Qes[x].push_back( T ); T.en=x; Qes[y].push_back( T ); } for( int i=1;i<=N; i++ ) { if( visit[i]==0 )//多棵树的情况,因为同一棵树任何一个节点都可以做根节点 { LCA( i,0,i ); } } for( int i=1;i<=m ; i++ ) { if( ans[i]==-1 ) { printf( "Not connected\n" ); } else printf( "%d\n",ans[i] ); } } return 0; }
Interviewe
/*RMQ*/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=200010, A=1001; int a[N]; int n,k; int st[N][20],lg2[N]; void ST(int *a,int n) { lg2[0]=-1; for(int i=1;i<=n;i++) lg2[i]=lg2[i-1]+(i&(i-1)?0:1); for(int i=0;i<n;i++) st[i][0]=a[i]; for(int j=1;j<=lg2[n];j++) for(int i=0;lg2[n-i]>=j;i++) st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]); } int RMQ(int x,int y) { int k=lg2[y-x+1]; return max(st[x][k],st[y-(1<<k)+1][k]); } bool ok(int c) { int t=n/c, s=0; for(int i=0;i<c;i++) s+=RMQ(t*i,t*i+t-1); return s>k; } int main() { while(scanf("%d%d",&n,&k),n>=0 || k>=0) { int s=0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); s+=a[i]; } if(s<=k) {printf("-1\n"); continue;} ST(a,n); int l=1, r=n; while(l<r) { int m=(l+r)/2; if(ok(m)) r=m; else l=m+1; } printf("%d\n",l); } return 0; }
Check Corners
/*本题碉堡了,内存限制好紧,再大一点都不行,还只能用int,开始用short WA了好多次。。。。。 题意:给一个矩阵,然后给Q个询问,每个询问有四个数,分别代表询问的子矩阵的左上角和右下角,然后找出子矩阵的最大值输出,然后再把这个值与子矩阵的四个角的值比较,如果有至少一个等于这个最大值就输出“yes”,否则输出“no”。*/#include <stdio.h>#include <iostream>#include <math.h>using namespace std;const int N = 302;int n, m;int val[N][N];int dpmax[N][N][9][9];void ST(){ int i, j, r, c, k1, k2; for(i=1;i<=n;i++) for(j=1;j<=m;j++) dpmax[i][j][0][0]=val[i][j]; k1=(int)(log(double(n))/log(2.0)); k2=(int)(log(double(m))/log(2.0)); for(i=0;i<=k1;i++) { for(j=0;j<=k2;j++) { if(i==0&&j==0) continue; for(r=1;r+(1<<i)-1<=n;r++) { for(c=1;c+(1<<j)-1<=m;c++) { if(i==0) dpmax[r][c][i][j]=max(dpmax[r][c][i][j-1],dpmax[r][c+(1<<(j-1))][i][j-1]); else dpmax[r][c][i][j]=max(dpmax[r][c][i-1][j],dpmax[r+(1<<(i-1))][c][i-1][j]); } } } }}int query(int r1, int c1, int r2, int c2){ int kr=(int)(log(double(r2-r1+1))/log(2.0)); int kc=(int)(log(double(c2-c1+1))/log(2.0)); int t1=dpmax[r1][c1][kr][kc]; int t2=dpmax[r2-(1<<kr)+1][c1][kr][kc]; int t3=dpmax[r1][c2-(1<<kc)+1][kr][kc]; int t4=dpmax[r2-(1<<kr)+1][c2-(1<<kc)+1][kr][kc]; return max(max(t1,t2),max(t3,t4));}int main(){ int i, j, k; int r1,c1,r2,c2; while(~scanf("%d%d",&n,&m)) { for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&val[i][j]); ST(); scanf("%d",&k); while(k--) { scanf("%d%d%d%d",&r1,&c1,&r2,&c2); int ret=query(r1,c1,r2,c2); printf("%d ",ret); if(val[r1][c1]==ret||val[r1][c2]==ret||val[r2][c1]==ret||val[r2][c2]==ret) puts("yes"); else puts("no"); } } return 0;}
Cow Sorting
/*话说这道题要用的三个树状数组,不容易啊。我刚开始想的时候想明白了用公式怎么算,却想不出来怎么转化到树状数组上,总感觉有些地方实现不了,原来竟然是用三个树状数组。。。这让只写过一个树状数组的孩纸情何以堪? 具体来说,有一个num数组,里面记录的是插入a[i]后, 在a[i]之前插入且比a[i]小的数的个数;还有一个totalsum数组, 记录的是插入第i个数后,前i-1个数的总和;还有一个smallersum数组, 记录的是插入a[i]后,在a[i]之前插入且比a[i] 小的数的总和。 这样最后就可以算出来了。 */ #include <cstdio>#include <stdlib.h>#include <string.h>#include <algorithm>using namespace std;const int M = 100010;__int64 num[M] , totalsum[M] , smallsum[M];__int64 lowbit( __int64 x ){ return x&(-x); }void add( __int64 x[] , __int64 xx , __int64 yy ){ while( xx < M ) { x[xx] += yy; xx +=lowbit(xx); }}__int64 sum( __int64 x[] , __int64 xx ){ __int64 ss = 0; while( xx > 0 ) { ss += x[xx]; xx -= lowbit(xx); } return ss;}int main( ){ __int64 n; while( ~scanf("%I64d",&n) ) { memset( num , 0 , sizeof(num) ); memset( totalsum , 0 , sizeof(totalsum) ); memset( smallsum , 0 , sizeof(smallsum) ); __int64 x , ans = 0 , count = 0; for( __int64 i=1 ; i<=n ; i++ ){ scanf("%I64d",&x); add( num , x , 1 ); add( totalsum , i , x ); add( smallsum , x , x ); count = sum( num , x-1 ); ans += (i-count-1)*x; ans += sum(totalsum,i-1); ans -= sum(smallsum,x-1); } printf("%I64d\n",ans); } return 0;}