题目大意:
有N层楼,每层楼都有两个门,i 层楼的两扇门到i+1层楼的两扇门各有通道互不影响(例如:i层楼门号有1、2,i+1层楼门号有1、2则有四条通道 1->1、1->2、2-> 1 、2-> 2),其中可以修改通道的状态,如果op值为‘1’的时候 将x楼与x+1层楼之间的y-z门的这条通道的状态改变,如果先前是通路则切断无法通过,如果先前是断路的状态,则恢复通路可以通过。如果op为‘0’,在表示询问a->b 有多少种路径可以到达。
解题思路:
线段数,节点存储通道路径的矩阵,矩阵的相乘结果刚好是下一层楼四条边的路径种类和,之前用的方法是想,计算左边门和右边门的所有情况和,然后加和,但是难判断的是上一层的右边得到的路径种类和以及左边得到的路径种类和,汇流到了下一层的左边边门和右边门时,很难分配该层的到下一层的左右门各有多少条路径,反正说不太清,代码编的就很乱,不想在改了。 正好利用矩阵完美解决了路径汇总到下一层左右门时路径种类个数的问题,最后计算出矩阵,然后将矩阵里所有的值相加就是答案。
代码:
1 #include <algorithm> 2 #include <iostream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <string> 8 #include <bitset> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <cmath> 13 #include <list> 14 //#include <map> 15 #include <set> 16 using namespace std; 17 /***************************************/ 18 #define ll long long 19 #define int64 __int64 20 #define PI 3.1415927 21 /***************************************/ 22 const int INF = 0x7f7f7f7f; 23 const double eps = 1e-8; 24 const double PIE=acos(-1.0); 25 const int d1x[]= {0,-1,0,1}; 26 const int d1y[]= {-1,0,1,0}; 27 const int d2x[]= {0,-1,0,1}; 28 const int d2y[]= {1,0,-1,0}; 29 const int fx[]= {-1,-1,-1,0,0,1,1,1}; 30 const int fy[]= {-1,0,1,-1,1,-1,0,1}; 31 const int dirx[]= {-1,1,-2,2,-2,2,-1,1}; 32 const int diry[]= {-2,-2,-1,-1,1,1,2,2}; 33 /*vector <int>map[N];map[a].push_back(b);int len=map[v].size();*/ 34 /***************************************/ 35 void openfile() 36 { 37 freopen("data.in","rb",stdin); 38 freopen("data.out","wb",stdout); 39 } 40 priority_queue<int> qi1; 41 priority_queue<int, vector<int>, greater<int> >qi2; 42 /**********************华丽丽的分割线,以上为模板部分*****************/ 43 const int M=50010; 44 const int64 MOD=1000000007; 45 struct tree 46 { 47 int64 matrix[3][3]; 48 int left,right; 49 } node[M*4]; //需开四倍的空间大小 50 int64 cnt; 51 tree pp; 52 tree mul(tree a,tree b,int l,int r) 53 { 54 int i,j,k; 55 memset(pp.matrix,0,sizeof(pp.matrix)); 56 pp.left=l; 57 pp.right=r; 58 for(i=1; i<=2; i++) 59 for(j=1; j<=2; j++) 60 for(k=1; k<=2; k++) 61 { 62 pp.matrix[i][j]+=a.matrix[i][k]%MOD*b.matrix[k][j]%MOD; 63 pp.matrix[i][j]%=MOD; 64 } 65 return pp; 66 } 67 void build__tree(int id,int l,int r) //建树 68 { 69 int mid=(l+r)/2; 70 node[id].left=l; //初始化赋值区间的坐标 71 node[id].right=r; 72 if (l==r) 73 { 74 node[id].matrix[1][1]=1; 75 node[id].matrix[1][2]=1; 76 node[id].matrix[2][1]=1; 77 node[id].matrix[2][2]=1; 78 return ; 79 } 80 build__tree(id*2,l,mid); //左孩子 81 build__tree(id*2+1,mid+1,r); //右孩子 82 node[id]=mul(node[id*2],node[id*2+1],l,r); 83 return ; 84 } 85 tree tmp; 86 int query(int id,int l,int r) //查询区间的总和 87 { 88 int mid=(node[id].left+node[id].right)/2; 89 if (node[id].left==l&&node[id].right==r) 90 { 91 tmp=mul(tmp,node[id],l,r); 92 } 93 else if (l>mid) //[l,r]在右孩子部分 94 query(id*2+1,l,r); 95 else if (r<=mid) // [l,r]在左孩子部分 96 query(id*2,l,r); 97 else //[l,r]区间,左右孩子都有分别递归。 98 { 99 query(id*2,l,mid); 100 query(id*2+1,mid+1,r); 101 } 102 return 0; 103 } 104 void updata(int id,int pos,int y,int z) //从上向下寻找节点,找到节点后然后从下往上更新节点的val值 105 { 106 if (node[id].left==pos&&node[id].right==pos)//找到该节点 107 { 108 node[id].matrix[y][z]=1-node[id].matrix[y][z]; 109 return ; 110 } 111 int mid=(node[id].left+node[id].right)/2; 112 if (pos<=mid) //节点在左孩子部分 113 updata(id*2,pos,y,z); 114 else //节点在右孩子部分 115 updata(id*2+1,pos,y,z); 116 node[id]=mul(node[id*2],node[id*2+1],node[id].left,node[id].right); 117 } 118 int main() 119 { 120 int n,m; 121 while(scanf("%d%d",&n,&m)!=EOF) 122 { 123 build__tree(1,1,n-1); 124 int op; 125 int i; 126 for(i=0; i<m; i++) 127 { 128 scanf("%d",&op); 129 if (!op) 130 { 131 tmp.matrix[1][1]=1; 132 tmp.matrix[1][2]=0; 133 tmp.matrix[2][1]=0; 134 tmp.matrix[2][2]=1; 135 int a,b; 136 scanf("%d%d",&a,&b); 137 query(1,a,b-1); 138 cnt=0; 139 for(int i=1;i<=2;i++) 140 for(int j=1;j<=2;j++) 141 { 142 cnt+=tmp.matrix[i][j]%MOD; 143 cnt%=MOD; 144 } 145 printf("%I64d ",cnt); 146 } 147 else 148 { 149 int x,y,z; 150 scanf("%d%d%d",&x,&y,&z); 151 updata(1,x,y,z); 152 } 153 } 154 memset(node,0,sizeof(node)); 155 } 156 return 0; 157 }
错误的代码:
很乱,但是编了好长时间 ,舍不得,回头有时间在看看把。
1 #include <algorithm> 2 #include <iostream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <string> 8 #include <bitset> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <cmath> 13 #include <list> 14 //#include <map> 15 #include <set> 16 using namespace std; 17 /***************************************/ 18 #define ll long long 19 #define int64 __int64 20 #define PI 3.1415927 21 /***************************************/ 22 const int INF = 0x7f7f7f7f; 23 const double eps = 1e-8; 24 const double PIE=acos(-1.0); 25 const int d1x[]= {0,-1,0,1}; 26 const int d1y[]= {-1,0,1,0}; 27 const int d2x[]= {0,-1,0,1}; 28 const int d2y[]= {1,0,-1,0}; 29 const int fx[]= {-1,-1,-1,0,0,1,1,1}; 30 const int fy[]= {-1,0,1,-1,1,-1,0,1}; 31 const int dirx[]= {-1,1,-2,2,-2,2,-1,1}; 32 const int diry[]= {-2,-2,-1,-1,1,1,2,2}; 33 /*vector <int>map[N];map[a].push_back(b);int len=map[v].size();*/ 34 /***************************************/ 35 void openfile() 36 { 37 freopen("data.in","rb",stdin); 38 freopen("data.out","wb",stdout); 39 } 40 priority_queue<int> qi1; 41 priority_queue<int, vector<int>, greater<int> >qi2; 42 /**********************华丽丽的分割线,以上为模板部分*****************/ 43 const int M=50010; 44 const long long MOD=1000000007; 45 struct tree 46 { 47 long long sum; 48 long long sum1,sum2; 49 long long x,y; 50 long long d[5]; 51 int left,right; //记录区间的左右闭区间坐标 52 } node[M*4]; //需开四倍的空间大小 53 long long cnt1,cnt2; 54 long long aaans; 55 void MM() 56 { 57 long long b=MOD-2; 58 long long ans=1; 59 long long a=2; 60 while(b) 61 { 62 if (b&1) 63 ans=(ans%MOD*a%MOD)%MOD; 64 a=(a%MOD*a%MOD)%MOD; 65 b>>=1; 66 } 67 aaans=ans; 68 return ; 69 } 70 long long aaans1; 71 void MMM() 72 { 73 long long b=MOD-2; 74 long long ans=1; 75 long long a=4; 76 while(b) 77 { 78 if (b&1) 79 ans=(ans%MOD*a%MOD)%MOD; 80 a=(a%MOD*a%MOD)%MOD; 81 b>>=1; 82 } 83 aaans1=ans; 84 return ; 85 } 86 void build__tree(int id,int l,int r) //建树 87 { 88 int mid=(l+r)/2; 89 node[id].left=l; //初始化赋值区间的坐标 90 node[id].right=r; 91 for(int i=1; i<=4; i++) 92 node[id].d[i]=1; 93 if (l==r) 94 { 95 node[id].sum1=2; //初始化区间节点的val值 96 node[id].sum2=2; 97 node[id].x=2; 98 node[id].y=2; 99 node[id].sum=node[id].sum1+node[id].sum2; 100 return ; 101 } 102 build__tree(id*2,l,mid); //左孩子 103 build__tree(id*2+1,mid+1,r); //右孩子 104 node[id].x=node[id*2+1].x; 105 node[id].y=node[id*2+1].y; 106 node[id].sum=(node[id*2].sum%MOD*node[id*2+1].sum%MOD)%MOD*aaans%MOD; 107 node[id].sum1=(node[id].sum%MOD*node[id].x%MOD)%MOD*aaans1%MOD; 108 node[id].sum2=(node[id].sum%MOD*node[id].y%MOD)%MOD*aaans1%MOD; 109 } 110 int query(int id,int l,int r) //查询区间的总和 111 { 112 int mid=(node[id].left+node[id].right)/2; 113 if (node[id].left==l&&node[id].right==r) 114 { 115 cnt1=(cnt1*node[id].sum1)%MOD; 116 cnt2=(cnt2*node[id].sum2)%MOD; 117 return 0; 118 } 119 else if (l>mid) //[l,r]在右孩子部分 120 query(id*2+1,l,r); 121 else if (r<=mid) // [l,r]在左孩子部分 122 query(id*2,l,r); 123 else //[l,r]区间,左右孩子都有分别递归。 124 { 125 query(id*2,l,mid); 126 query(id*2+1,mid+1,r); 127 } 128 return 0; 129 } 130 void updata(int id,int pos,int val) //从上向下寻找节点,找到节点后然后从下往上更新节点的val值 131 { 132 if (node[id].left==pos&&node[id].right==pos)//找到该节点 133 { 134 if (node[id].d[val]==1) 135 { 136 node[id].d[val]=0; 137 if (val%2) 138 { 139 node[id].x--; 140 node[id].sum1--; 141 } 142 else 143 { 144 node[id].y--; 145 node[id].sum2--; 146 } 147 } 148 else 149 { 150 node[id].d[val]=1; 151 if (val%2) 152 { 153 node[id].x++; 154 node[id].sum1++; 155 } 156 else 157 { 158 node[id].y++; 159 node[id].sum2++; 160 } 161 } 162 node[id].sum=node[id].sum1+node[id].sum2; 163 return ; 164 } 165 int mid=(node[id].left+node[id].right)/2; 166 if (pos<=mid) //节点在左孩子部分 167 updata(id*2,pos,val); 168 else //节点在右孩子部分 169 updata(id*2+1,pos,val); 170 node[id].x=node[id*2+1].x; 171 node[id].y=node[id*2+1].y; 172 int b; 173 int ans; 174 if (node[id*2].sum*node[id*2+1].sum<4) 175 { 176 node[id].sum1=node[id*2].sum1%MOD*node[id*2+1].sum1%MOD; 177 node[id].sum2=node[id*2].sum2%MOD*node[id*2+1].sum2%MOD; 178 node[id].sum=(node[id].sum1+node[id].sum2)%MOD; 179 } 180 else 181 { 182 long long a=node[id].x+node[id].y; 183 node[id].sum=(node[id*2].sum%MOD*node[id*2+1].sum%MOD)%MOD*aaans%MOD; 184 /*ans=1; 185 a=node[id].x+node[id].y; 186 b=MOD-2; 187 while(b) 188 { 189 if (b&1) 190 ans=(ans%MOD*a%MOD)%MOD; 191 a=(a%MOD*a%MOD)%MOD; 192 b>>=1; 193 } */ 194 if (a) 195 { 196 node[id].sum1=(node[id].sum%MOD*node[id].x%MOD)%MOD/a%MOD; 197 node[id].sum2=(node[id].sum%MOD*node[id].y%MOD)%MOD/a%MOD; 198 } 199 else 200 { 201 node[id].sum1=0; 202 node[id].sum2=0; 203 } 204 } 205 } 206 int main() 207 { 208 int n,m; 209 MM(); 210 MMM(); 211 while(scanf("%d%d",&n,&m)!=EOF) 212 { 213 build__tree(1,1,n-1); 214 int op; 215 int i; 216 for(i=0; i<m; i++) 217 { 218 scanf("%d",&op); 219 if (!op) 220 { 221 int a,b; 222 cnt1=1; 223 cnt2=1; 224 scanf("%d%d",&a,&b); 225 query(1,a,b-1); 226 printf("%I64d ",(cnt1+cnt2)%MOD); 227 } 228 else 229 { 230 int x,y,z; 231 scanf("%d%d%d",&x,&y,&z); 232 int ce=0; 233 if (y==1&&z==1) 234 ce=1; 235 if (y==1&&z==2) 236 ce=2; 237 if (y==2&&z==1) 238 ce=3; 239 if (y==2&&z==2) 240 ce=4; 241 updata(1,x,ce); 242 } 243 } 244 } 245 return 0; 246 } 247 /* 248 50000 100 249 0 1 50000 250 0 2 50000 251 0 10000 10001 252 0 10000 10010 253 1 10000 1 1 254 1 10010 2 1 255 1 10000 2 1 256 1 10000 1 2 257 0 10000 50000 258 0 10000 10001 259 0 10000 10002 260 0 10000 10003 261 0 10000 10004 262 0 10000 10005 263 0 10000 10006 264 0 10000 10007 265 0 10000 10008 266 0 10000 10009 267 0 10000 10010 268 0 10000 10011 269 0 10000 10012 270 0 1 2 271 0 1 3 272 0 1 4 273 0 1 5 274 0 1 6 275 0 2 3 276 0 2 4 277 0 2 5 278 0 3 4 279 0 3 5 280 0 3 6 281 0 4 5 282 0 4 6 283 0 5 6 284 */ 285 /* 286 50000 100 287 1 3 1 1 288 1 3 2 1 289 1 3 1 2 290 1 1 1 1 291 1 1 2 1 292 1 1 1 2 293 1 2 1 1 294 1 2 2 1 295 1 2 1 2 296 0 1 50000 297 0 2 50000 298 0 3 50000 299 0 4 50000 300 0 10000 10001 301 0 10000 50000 302 */