matrix_last_acm_2
2014年广州站网络赛 北大命题 password 123
B http://acm.hust.edu.cn/vjudge/contest/view.action?cid=97257#problem/B
题意:长度为n的墙,一开始1-n都是2号颜色,m次操作,P是将a到b都涂成c号,Q是查询a到b之间内有哪些颜色,从小到大输出。
解法:颜色只有30种,可以用30位二进制表示某种颜色有或者没有,1表示有,0表示没有,线段树根节点就是两个儿子的二进制或。
1 //#define debug 2 //#define txtout 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<cctype> 8 #include<ctime> 9 #include<iostream> 10 #include<algorithm> 11 #include<vector> 12 #include<queue> 13 #include<stack> 14 #include<map> 15 #include<set> 16 #define mt(a,b) memset(a,b,sizeof(a)) 17 using namespace std; 18 typedef long long LL; 19 const double eps=1e-8; 20 const double pi=acos(-1.0); 21 const int inf=0x3f3f3f3f; 22 const int M=1e5+10; 23 struct OP{ 24 char str[4]; 25 int a,b,c; 26 }op[M]; 27 int n,m; 28 #define lrrt int L,int R,int rt 29 #define iall 1,n,1 30 #define imid int mid=(L+R)>>1 31 #define lson L,mid,rt<<1 32 #define rson mid+1,R,rt<<1|1 33 struct T{ 34 int state,lazy; 35 }tree[(M*10)<<2]; 36 void pushup(int rt){ 37 tree[rt].state=tree[rt<<1].state|tree[rt<<1|1].state; 38 } 39 void pushdown(int rt){ 40 if(tree[rt].lazy){ 41 tree[rt<<1].lazy=tree[rt].lazy; 42 tree[rt<<1|1].lazy=tree[rt].lazy; 43 tree[rt<<1].state=tree[rt].lazy; 44 tree[rt<<1|1].state=tree[rt].lazy; 45 tree[rt].lazy=0; 46 } 47 } 48 void build(lrrt){ 49 tree[rt].lazy=0; 50 if(L==R){ 51 tree[rt].state=2; 52 return ; 53 } 54 imid; 55 build(lson); 56 build(rson); 57 pushup(rt); 58 } 59 void update(int x,int y,int z,lrrt){ 60 if(x<=L&&R<=y){ 61 tree[rt].state=z; 62 tree[rt].lazy=z; 63 return ; 64 } 65 imid; 66 pushdown(rt); 67 if(mid>=x) update(x,y,z,lson); 68 if(mid<y) update(x,y,z,rson); 69 pushup(rt); 70 } 71 int query(int x,int y,lrrt){ 72 if(x<=L&&R<=y) return tree[rt].state; 73 imid; 74 pushdown(rt); 75 int ans=0; 76 if(mid>=x) ans|=query(x,y,lson); 77 if(mid<y) ans|=query(x,y,rson); 78 return ans; 79 } 80 void solve(){ 81 build(iall); 82 for(int i=0;i<m;i++){ 83 if(op[i].str[0]=='P'){ 84 update(op[i].a,op[i].b,1<<(op[i].c-1),iall); 85 continue; 86 } 87 op[i].c=query(op[i].a,op[i].b,iall); 88 } 89 } 90 int main(){ 91 #ifdef txtout 92 freopen("in.txt","r",stdin); 93 freopen("out.txt","w",stdout); 94 #endif 95 while(~scanf("%d%d",&n,&m),n|m){ 96 for(int i=0;i<m;i++){ 97 scanf("%s%d%d",op[i].str,&op[i].a,&op[i].b); 98 if(op[i].str[0]=='Q') continue; 99 scanf("%d",&op[i].c); 100 } 101 solve(); 102 for(int i=0;i<m;i++){ 103 if(op[i].str[0]=='P') continue; 104 bool out=false; 105 for(int j=0;j<30;j++){ 106 if((op[i].c>>j)&1){ 107 if(out) putchar(' '); 108 printf("%d",j+1); 109 out=true; 110 } 111 } 112 puts(""); 113 } 114 } 115 return 0; 116 }
C http://acm.hust.edu.cn/vjudge/contest/view.action?cid=97257#problem/C
题意:n*n的矩阵,.可以走,#不能走。8个方向走,上下左右,还有45度的四个方向。最多只能转弯一次且一定要转90度,问最长的路径的长度。
解法:先预处理出每个点8个方向最远能走的长度。然后枚举每个起点,枚举8个方向,每走一步都尝试左转90和右转90,取最大值。
1 //#define debug 2 //#define txtout 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<cctype> 8 #include<ctime> 9 #include<iostream> 10 #include<algorithm> 11 #include<vector> 12 #include<queue> 13 #include<stack> 14 #include<map> 15 #include<set> 16 #define mt(a,b) memset(a,b,sizeof(a)) 17 using namespace std; 18 typedef long long LL; 19 const double eps=1e-8; 20 const double pi=acos(-1.0); 21 const int inf=0x3f3f3f3f; 22 const int M=1e2+10; 23 char a[M][M]; 24 int dp[M][M][8]; 25 int n; 26 int dx[]={-1,-1,0,1,1,1,0,-1}; 27 int dy[]={0,1,1,1,0,-1,-1,-1}; 28 bool inside(int x,int y){ 29 return x>=0&&x<n&&y>=0&&y<n; 30 } 31 void init_dp(){ 32 for(int i=0;i<n;i++){ 33 for(int j=0;j<n;j++){ 34 for(int k=0;k<8;k++){ 35 dp[i][j][k]=0; 36 int tx=i; 37 int ty=j; 38 while(inside(tx,ty)&&a[tx][ty]=='.'){ 39 dp[i][j][k]++; 40 tx+=dx[k]; 41 ty+=dy[k]; 42 } 43 } 44 } 45 } 46 } 47 int solve(){ 48 init_dp(); 49 int res=0; 50 for(int i=0;i<n;i++){ 51 for(int j=0;j<n;j++){ 52 if(a[i][j]=='#') continue; 53 for(int k=0;k<8;k++){ 54 int step=0; 55 int tx=i; 56 int ty=j; 57 while(inside(tx,ty)&&a[tx][ty]=='.'){ 58 res=max(res,step+dp[tx][ty][(k+2)%8]); 59 res=max(res,step+dp[tx][ty][(k-2+8)%8]); 60 tx+=dx[k]; 61 ty+=dy[k]; 62 step++; 63 } 64 } 65 } 66 } 67 return res; 68 } 69 int main(){ 70 #ifdef txtout 71 freopen("in.txt","r",stdin); 72 freopen("out.txt","w",stdout); 73 #endif 74 while(~scanf("%d",&n),n){ 75 for(int i=0;i<n;i++){ 76 scanf("%s",a[i]); 77 } 78 printf("%d\n",solve()); 79 } 80 return 0; 81 }
D http://acm.hust.edu.cn/vjudge/contest/view.action?cid=97257#problem/D
题意:n*n的矩形,K起点,T终点,上下左右走,每一步一秒,到达终点前要集齐m个钥匙,钥匙编号要从小到大收集,第一次遇到的S要多花一秒,问最少几秒完成。
解法: bfs,状态 x y 拥有钥匙的最大号 key,蛇的状态 state,如果用队列,遇到s时杀了,要停在原地。另一种方法是直接进s,step+=2,需要优先队列。
1 //#define debug 2 //#define txtout 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<cctype> 8 #include<ctime> 9 #include<iostream> 10 #include<algorithm> 11 #include<vector> 12 #include<queue> 13 #include<stack> 14 #include<map> 15 #include<set> 16 #define mt(a,b) memset(a,b,sizeof(a)) 17 using namespace std; 18 typedef long long LL; 19 const double eps=1e-8; 20 const double pi=acos(-1.0); 21 const int inf=0x3f3f3f3f; 22 const int M=1e2+10; 23 char a[M][M]; 24 int n,m; 25 struct Q{ 26 int x,y,key,state; 27 }now,pre; 28 queue<Q> q; 29 int dist[M][M][10][1<<5]; 30 int length_of_snake; 31 int snake[M][M]; 32 int dx[]={0,0,1,-1}; 33 int dy[]={1,-1,0,0}; 34 void init_snake(){ 35 length_of_snake=0; 36 for(int i=0;i<n;i++){ 37 for(int j=0;j<n;j++){ 38 if(a[i][j]!='S') continue; 39 snake[i][j]=length_of_snake++; 40 } 41 } 42 } 43 void init(){ 44 init_snake(); 45 int big=1<<length_of_snake; 46 for(int i=0;i<n;i++){ 47 for(int j=0;j<n;j++){ 48 for(int k=0;k<=m;k++){ 49 for(int s=0;s<big;s++){ 50 dist[i][j][k][s]=inf; 51 } 52 } 53 } 54 } 55 while(!q.empty()) q.pop(); 56 } 57 void want_to_push(int x,int y,int key,int state,int step){ 58 if(dist[x][y][key][state]>step){ 59 dist[x][y][key][state]=step; 60 now.x=x; 61 now.y=y; 62 now.key=key; 63 now.state=state; 64 q.push(now); 65 } 66 } 67 void get_start(){ 68 for(int i=0;i<n;i++){ 69 for(int j=0;j<n;j++){ 70 if(a[i][j]!='K') continue; 71 want_to_push(i,j,0,0,0); 72 return ; 73 } 74 } 75 } 76 bool inside(int x,int y){ 77 return x>=0&&x<n&&y>=0&&y<n; 78 } 79 int solve(){ 80 init(); 81 get_start(); 82 while(!q.empty()){ 83 pre=q.front(); 84 q.pop(); 85 for(int i=0;i<4;i++){ 86 int tx=pre.x+dx[i]; 87 int ty=pre.y+dy[i]; 88 if(!inside(tx,ty)) continue; 89 if(a[tx][ty]=='#') continue; 90 int pre_step=dist[pre.x][pre.y][pre.key][pre.state]; 91 if(a[tx][ty]=='T'){ 92 if(pre.key==m) return pre_step+1; 93 want_to_push(tx,ty,pre.key,pre.state,pre_step+1); 94 continue; 95 } 96 if(a[tx][ty]=='S'){ 97 if((pre.state>>snake[tx][ty])&1){ 98 want_to_push(tx,ty,pre.key,pre.state,pre_step+1); 99 continue; 100 } 101 want_to_push(pre.x,pre.y,pre.key,pre.state|(1<<snake[tx][ty]),pre_step+1); 102 continue; 103 } 104 if(isdigit(a[tx][ty])){ 105 if(pre.key+1==a[tx][ty]-'0'){ 106 want_to_push(tx,ty,pre.key+1,pre.state,pre_step+1); 107 continue; 108 } 109 } 110 want_to_push(tx,ty,pre.key,pre.state,pre_step+1); 111 } 112 } 113 return -1; 114 } 115 int main(){ 116 #ifdef txtout 117 freopen("in.txt","r",stdin); 118 freopen("out.txt","w",stdout); 119 #endif 120 while(~scanf("%d%d",&n,&m),n|m){ 121 for(int i=0;i<n;i++){ 122 scanf("%s",a[i]); 123 } 124 int ans=solve(); 125 if(ans==-1){ 126 puts("impossible"); 127 continue; 128 } 129 printf("%d\n",ans); 130 } 131 return 0; 132 }
H http://acm.hust.edu.cn/vjudge/contest/view.action?cid=97257#problem/H
题意:给一颗树,n个节点。给m次操作,每次操作x到y路径上的每一个点都增加一个种类编号是z的物品,最后问每一个节点 个数最多的种类编号,如果有多个个数相同的种类,输出编号最小的。如果没有物品输出0.
解法:1.树链剖分转化为一维线段的同样的问题。2.对区间x到y增加一个z,可以用一个数组vector存,x位置存z,y+1位置存-z。把所有的操作都存好后,遍历线段上的点,将该点上vector存的都加入线段树中,最后在线段树查最大个数的下标。线段树1-z,每一个位置代表种类为i 的个数。
1 //#define debug 2 //#define txtout 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<cctype> 8 #include<ctime> 9 #include<iostream> 10 #include<algorithm> 11 #include<vector> 12 #include<queue> 13 #include<stack> 14 #include<map> 15 #include<set> 16 #define mt(a,b) memset(a,b,sizeof(a)) 17 using namespace std; 18 typedef long long LL; 19 const double eps=1e-8; 20 const double pi=acos(-1.0); 21 const int inf=0x3f3f3f3f; 22 const int M=1e5+10; 23 int n,m; 24 struct E { 25 int u,v; 26 } e[M]; 27 struct C { 28 int x,y,z; 29 } c[M]; 30 vector<int> lazy[M]; 31 int answer[M]; 32 int to_id[M]; 33 int big_z; 34 class Shu_Lian_Pou_Fen { ///树链剖分 35 static const int MV=1e5+10; ///点的个数 36 struct G { 37 struct E { 38 int v,next; 39 } e[MV<<1]; 40 int le,head[MV]; 41 void init(int n) { 42 le=0; 43 for(int i=0; i<=n; i++) head[i]=-1; 44 } 45 void add(int u,int v) { 46 e[le].v=v; 47 e[le].next=head[u]; 48 head[u]=le++; 49 } 50 } g; 51 public: 52 int n,Index,fa[MV],num[MV],son[MV],dep[MV],sid[MV],top[MV]; 53 void dfs(int u) { 54 num[u]=1; 55 son[u]=0; 56 for(int i=g.head[u]; ~i; i=g.e[i].next) { 57 int v=g.e[i].v; 58 if(v!=fa[u]) { 59 fa[v]=u; 60 dep[v]=dep[u]+1; 61 dfs(v); 62 if(num[son[u]]<num[v]) son[u]=v; 63 num[u]+=num[v]; 64 } 65 } 66 } 67 void get(int u,int Top) { 68 sid[u]=++Index; 69 top[u]=Top; 70 if(son[u]) get(son[u],Top); 71 for(int i=g.head[u]; ~i; i=g.e[i].next) { 72 int v=g.e[i].v; 73 if(v!=fa[u]&&v!=son[u]) { 74 get(v,v); 75 } 76 } 77 } 78 public: 79 void init(int tn) { ///传入点数下标1 开始 80 n=tn; 81 g.init(n); 82 } 83 void add(int u,int v) { 84 g.add(u,v); 85 g.add(v,u); 86 } 87 void solve() { 88 fa[1]=dep[1]=num[0]=Index=0; 89 dfs(1); 90 get(1,1); 91 } 92 void update(int x,int y,int z) { 93 lazy[x].push_back(z); 94 lazy[y+1].push_back(-z); 95 } 96 void work(int x,int y,bool edge_index,int z) { ///边编号(用深度大的点一一对应)传入true,点编号传false 97 int tx=top[x],ty=top[y]; 98 while(tx!=ty) { 99 if(dep[tx]<dep[ty]) { 100 swap(tx,ty); 101 swap(x,y); 102 } 103 update(sid[tx],sid[x],z); 104 x=fa[tx]; 105 tx=top[x]; 106 } 107 if(edge_index) { 108 if(x==y) return ; 109 if(dep[x]>dep[y]) swap(x,y); 110 update(sid[son[x]],sid[y],z); 111 return ; 112 } 113 if(dep[x]>dep[y]) swap(x,y); 114 update(sid[x],sid[y],z); 115 } 116 }gx; 117 void init_lazy() { 118 gx.init(n); 119 for(int i=0;i<n-1;i++){ 120 gx.add(e[i].u,e[i].v); 121 } 122 gx.solve(); 123 for(int i=1;i<=n;i++){ 124 lazy[i].clear(); 125 } 126 for(int i=0;i<m;i++){ 127 gx.work(c[i].x,c[i].y,false,c[i].z); 128 } 129 } 130 #define lrrt int L,int R,int rt 131 #define iall 1,big_z,1 132 #define imid int mid=(L+R)>>1 133 #define lson L,mid,rt<<1 134 #define rson mid+1,R,rt<<1|1 135 struct T{ 136 int value,sum; 137 }tree[M<<2]; 138 void pushup(int rt){ 139 if(tree[rt<<1].sum>=tree[rt<<1|1].sum){ 140 tree[rt].value=tree[rt<<1].value; 141 tree[rt].sum=tree[rt<<1].sum; 142 } 143 else{ 144 tree[rt].value=tree[rt<<1|1].value; 145 tree[rt].sum=tree[rt<<1|1].sum; 146 } 147 if(tree[rt].sum==0){ 148 tree[rt].value=0; 149 } 150 } 151 void build(lrrt){ 152 if(L==R){ 153 tree[rt].value=L; 154 tree[rt].sum=0; 155 return ; 156 } 157 imid; 158 build(lson); 159 build(rson); 160 pushup(rt); 161 } 162 void update(int x,int y,lrrt){ 163 if(L==R){ 164 tree[rt].sum+=y; 165 return ; 166 } 167 imid; 168 if(mid>=x) update(x,y,lson); 169 else update(x,y,rson); 170 pushup(rt); 171 } 172 int get_big_z(){ 173 int res=0; 174 for(int i=1;i<m;i++){ 175 if(c[res].z<c[i].z){ 176 res=i; 177 } 178 } 179 return c[res].z; 180 } 181 void solve() { 182 if(m==0){ 183 for(int i=1;i<=n;i++){ 184 answer[i]=0; 185 } 186 return ; 187 } 188 init_lazy(); 189 big_z=get_big_z(); 190 build(iall); 191 for(int i=1;i<=n;i++){ 192 to_id[gx.sid[i]]=i; 193 } 194 for(int i=1;i<=n;i++){ 195 int len=lazy[i].size(); 196 for(int j=0;j<len;j++){ 197 int value=lazy[i][j]; 198 int add=1; 199 if(value<0){ 200 value=-value; 201 add=-1; 202 } 203 update(value,add,iall); 204 } 205 answer[to_id[i]]=tree[1].value; 206 } 207 } 208 int main() { 209 #ifdef txtout 210 freopen("in.txt","r",stdin); 211 freopen("out.txt","w",stdout); 212 #endif 213 while(~scanf("%d%d",&n,&m),n|m) { 214 for(int i=0; i<n-1; i++) { 215 scanf("%d%d",&e[i].u,&e[i].v); 216 } 217 for(int i=0; i<m; i++) { 218 scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].z); 219 } 220 solve(); 221 for(int i=1; i<=n; i++) { 222 printf("%d\n",answer[i]); 223 } 224 } 225 return 0; 226 }
end