迷之查做题?!
于是我就被教练迷之查了一发做题进度。
虽然无力吐槽,然而我还是把这几道题都写(水)了。
查到我的题目是:BZOJ3529,BZOJ2243,BZOJ3065。
然而我一开始只写了BZOJ3529......
BZOJ3529:
先反演然后树状数组,对于每个值的f用nlog筛即可。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=1e5+1e2; 8 const int mod=0x7fffffff; 9 10 struct BinaryIndexTree { 11 int dat[maxn]; 12 #define lowbit(x) ( x & -x ) 13 inline void update(int pos,int x) { 14 while( pos < maxn ) 15 dat[pos] += x, 16 pos += lowbit(pos); 17 } 18 inline int query(int pos) { 19 int ret = 0; 20 while( pos ) 21 ret += dat[pos], 22 pos -= lowbit(pos); 23 return ret; 24 } 25 }bit; 26 27 struct QNode { 28 int n,m,a,id; 29 friend bool operator < (const QNode &a,const QNode &b) { 30 return a.a < b.a; 31 } 32 }ns[maxn]; 33 struct FNode { 34 int f,div; 35 friend bool operator < (const FNode &a,const FNode &b) { 36 return a.f < b.f; 37 } 38 }fs[maxn]; 39 40 int mu[maxn]; 41 int ans[maxn],n,m,t; 42 43 inline void pre() { 44 static int prime[maxn],cnt; 45 static char vis[maxn]; 46 mu[1] = 1; 47 for(int i=2;i<maxn;i++) { 48 if( !vis[i] ) 49 prime[++cnt] = i, 50 mu[i] = -1; 51 for(int j=1;j<=cnt&&i*prime[j]<maxn;j++) { 52 vis[i*prime[j]] = 1, 53 mu[i*prime[j]] = -mu[i]; 54 if( ! ( i % prime[j] ) ) { 55 mu[i*prime[j]] = 0; 56 break; 57 } 58 } 59 } 60 for(int i=1;i<maxn;i++) { 61 fs[i].div = i; 62 for(int j=i;j<maxn;j+=i) 63 fs[j].f += i; 64 } 65 } 66 67 inline int calc(int n,int m) { 68 int ret = 0 , lim = min(n,m); 69 for(int i=1,j;i<=lim;i=j+1) { 70 j = min( n / ( n / i ) , m / ( m / i ) ); 71 ret += ( n / i ) * ( m / i ) * ( bit.query(j) - bit.query(i-1) ); 72 } 73 return ret & mod; 74 } 75 76 inline void getans() { 77 sort(ns+1,ns+1+n); 78 sort(fs+1,fs+maxn); 79 int pos = 0; 80 for(int i=1;i<=n;i++) { 81 while( pos + 1 < maxn && fs[pos+1].f <= ns[i].a ) { 82 ++pos; 83 for(int j=fs[pos].div;j<maxn;j+=fs[pos].div) 84 bit.update(j,fs[pos].f*mu[j/fs[pos].div]); 85 } 86 ans[ns[i].id] = calc(ns[i].n,ns[i].m); 87 } 88 } 89 90 int main() { 91 scanf("%d",&n); 92 for(int i=1;i<=n;i++) 93 scanf("%d%d%d",&ns[i].n,&ns[i].m,&ns[i].a), 94 ns[i].id = i; 95 pre(); 96 getans(); 97 98 for(int i=1;i<=n;i++) 99 printf("%d\n",ans[i]); 100 101 return 0; 102 }
BZOJ2243:
树链剖分线段树维护节点颜色,具体就是维护两边颜色和中间颜色个数。
写一个Node类就好做多了。讲真的不明白他们代码为什么都写那么长QAQ。
记得链合并时一边需要reverse(因为我的线段树从左向右都是从上到下)。
对于lca为a或b的需要特判,或者通过两次判定deep省去特判。详见代码。
(分类讨论什么的,自己纸上画一画就明白了)
另外一开始query的时候没写push给WA了一回。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=1e5+1e2; 8 9 int s[maxn],t[maxn<<1],nxt[maxn<<1]; 10 int fa[maxn],dep[maxn],top[maxn],son[maxn],siz[maxn],id[maxn],cov[maxn]; 11 int in[maxn],bin[maxn]; 12 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],lazy[maxn<<3],cnt; 13 int n,m; 14 15 struct Node { 16 int cl,cr,sum; 17 friend Node operator + (const Node &a,const Node &b) { 18 return (Node){a.cl,b.cr,a.sum+b.sum-(a.cr==b.cl)}; 19 } 20 inline void fill(int c) { 21 cl = cr = c , sum = 1; 22 } 23 inline Node reverse() { 24 return (Node){cr,cl,sum}; 25 } 26 }ns[maxn<<3]; 27 28 inline void build(int pos,int ll,int rr) { 29 l[pos] = ll , r[pos] = rr; 30 if( ll == rr ) { 31 ns[pos].fill(bin[ll]); 32 return; 33 } 34 const int mid = ( ll + rr ) >> 1; 35 build(lson[pos]=++cnt,ll,mid); 36 build(rson[pos]=++cnt,mid+1,rr); 37 ns[pos] = ns[lson[pos]] + ns[rson[pos]]; 38 } 39 inline void push(int pos) { 40 if( lazy[pos] ) { 41 if( lson[pos] ) { 42 ns[lson[pos]].fill(lazy[pos]); 43 lazy[lson[pos]] = lazy[pos]; 44 } 45 if( rson[pos] ) { 46 ns[rson[pos]].fill(lazy[pos]); 47 lazy[rson[pos]] = lazy[pos]; 48 } 49 lazy[pos] = 0; 50 } 51 } 52 inline void update(int pos,int ll,int rr,int cc) { 53 if( rr < l[pos] || r[pos] < ll ) 54 return; 55 if( ll <= l[pos] && r[pos] <= rr ) { 56 ns[pos].fill(lazy[pos]=cc); 57 return; 58 } 59 push(pos); 60 update(lson[pos],ll,rr,cc); 61 update(rson[pos],ll,rr,cc); 62 ns[pos] = ns[lson[pos]] + ns[rson[pos]]; 63 } 64 inline Node query(int pos,int ll,int rr) { 65 if( ll <= l[pos] && r[pos] <= rr ) 66 return ns[pos]; 67 const int mid = ( l[pos] + r[pos] ) >> 1; 68 push(pos); 69 if( rr <= mid ) 70 return query(lson[pos],ll,rr); 71 else if( ll > mid ) 72 return query(rson[pos],ll,rr); 73 return query(lson[pos],ll,rr) + query(rson[pos],ll,rr); 74 } 75 76 inline void addedge(int from,int to) { 77 static int cnt = 0; 78 t[++cnt] = to , 79 nxt[cnt] = s[from] , s[from] = cnt; 80 } 81 inline void pre(int pos) { 82 siz[pos] = 1; 83 for(int at=s[pos];at;at=nxt[at]) 84 if( t[at] != fa[pos] ) { 85 dep[t[at]] = dep[pos] + 1, 86 fa[t[at]] = pos; 87 pre(t[at]); 88 siz[pos] += siz[t[at]]; 89 if( siz[t[at]] > siz[son[pos]] ) 90 son[pos] = t[at]; 91 } 92 } 93 inline void dfs(int pos) { 94 top[pos] = son[fa[pos]] == pos ? top[fa[pos]] : pos; 95 id[pos] = top[pos] == top[fa[pos]] ? id[fa[pos]] + 1 : 1; 96 for(int at=s[pos];at;at=nxt[at]) 97 if( t[at] != fa[pos] ) 98 dfs(t[at]); 99 if( !son[pos] ) { 100 for(int p=pos;;p=fa[p]) { 101 bin[id[p]] = in[p]; 102 if( p == top[pos] ) 103 break; 104 } 105 cov[top[pos]] = ++cnt; 106 build(cov[top[pos]],id[top[pos]],id[pos]); 107 } 108 } 109 inline void chain(int a,int b,int cc) { 110 while( top[a] != top[b] ) { 111 if( dep[top[a]] > dep[top[b]] ) { 112 update(cov[top[a]],id[top[a]],id[a],cc); 113 a = fa[top[a]]; 114 } 115 else { 116 update(cov[top[b]],id[top[b]],id[b],cc); 117 b = fa[top[b]]; 118 } 119 } 120 if( dep[a] > dep[b] ) 121 swap(a,b); 122 update(cov[top[a]],id[a],id[b],cc); 123 } 124 inline Node getans(int a,int b) { 125 if( dep[a] > dep[b] ) 126 swap(a,b); 127 Node qa = query(cov[top[a]],id[a],id[a]) , qb = query(cov[top[b]],id[b],id[b]); 128 while( top[a] != top[b] ) { 129 if( !( a && b ) ) 130 exit(0); 131 if( dep[top[a]] > dep[top[b]] ) { 132 qa = query(cov[top[a]],id[top[a]],id[a]) + qa; 133 a = fa[top[a]]; 134 } 135 else { 136 qb = query(cov[top[b]],id[top[b]],id[b]) + qb; 137 b = fa[top[b]]; 138 } 139 } 140 if( dep[a] > dep[b] ) 141 swap(a,b) , 142 swap(qa,qb); 143 qb = query(cov[top[a]],id[a],id[b]) + qb; 144 qa = qa.reverse() + qb; 145 return qa; 146 } 147 148 int main() { 149 static char com[10]; 150 scanf("%d%d",&n,&m); 151 for(int i=1;i<=n;i++) 152 scanf("%d",in+i); 153 for(int i=1,a,b;i<n;i++) { 154 scanf("%d%d",&a,&b); 155 addedge(a,b) , addedge(b,a); 156 } 157 pre(1); 158 dfs(1); 159 for(int i=1,a,b,cc;i<=m;i++) { 160 scanf("%s%d%d",com,&a,&b); 161 if( *com == 'C' ) { 162 scanf("%d",&cc); 163 chain(a,b,cc); 164 } 165 else { 166 Node ans = getans(a,b); 167 printf("%d\n",ans.sum); 168 } 169 } 170 171 return 0; 172 }
BZOJ3065:
带插入修改区间k小值?
平衡树套主席树?
对不起,我只会分块,分块大法好。直接进前20。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #define debug cout 4 using namespace std; 5 const int maxs=130,maxb=1220,blk=600; 6 7 int sou[maxs][maxb],rt[maxs][maxb],nxt[maxs],siz[maxs],sc; 8 int n,m,lastp,used,lastans; 9 10 inline void cpy(int* dst,int *sou,int len) { 11 int ite = ( len + 7 ) >> 3; 12 switch( len & 7 ) { 13 case 0: do{ *dst++ = *sou++; 14 case 1: *dst++ = *sou++; 15 case 2: *dst++ = *sou++; 16 case 3: *dst++ = *sou++; 17 case 4: *dst++ = *sou++; 18 case 5: *dst++ = *sou++; 19 case 6: *dst++ = *sou++; 20 case 7: *dst++ = *sou++; }while(ite--); 21 } 22 } 23 24 inline void reb(int id) { 25 cpy(rt[id]+1,sou[id]+1,siz[id]); 26 sort(rt[id]+1,rt[id]+1+siz[id]); 27 } 28 29 inline void getp(int k,int& rb,int& rk) { 30 rb = 1 , rk = k; 31 while( rk > siz[rb] && nxt[rb] ) { 32 rk -= siz[rb] , 33 rb = nxt[rb]; 34 } 35 } 36 37 inline int bin(int id,int k) { // returning the number of elements which < k in block id. 38 return lower_bound(rt[id]+1,rt[id]+1+siz[id],k) - rt[id] - 1; 39 } 40 inline int cont(int id,int l,int r,int k) { // returning the number of elements which < k in block id's range[l,r]. 41 int ret = 0; 42 for(int i=l;i<=r;i++) 43 ret += ( sou[id][i] < k ); 44 return ret; 45 } 46 47 inline int kth(int l,int r,int k) { 48 int lb,lpp,rb,rpp; 49 getp(l,lb,lpp) , getp(r,rb,rpp); 50 int ll = -1 , rr = 70001 , mid , lam; 51 while( rr > ll + 1 ) { 52 mid = ( ll + rr ) >> 1 , lam = 0; 53 if( lb == rb ) 54 lam = cont(lb,lpp,rpp,mid); 55 else { 56 lam = cont(lb,lpp,siz[lb],mid) + cont(rb,1,rpp,mid); 57 for(int pos=nxt[lb];pos!=rb;pos=nxt[pos]) 58 lam += bin(pos,mid); 59 } 60 if( lam < k ) 61 ll = mid; 62 else 63 rr = mid; 64 } 65 return ll; 66 } 67 inline void upd(int tar,int nv) { 68 int b,pp; 69 getp(tar,b,pp); 70 int i; 71 for(i=1;rt[b][i]!=sou[b][pp];i++) ; 72 sou[b][pp] = rt[b][i] = nv; 73 while( i < siz[b] && rt[b][i] > rt[b][i+1] ) 74 swap(rt[b][i],rt[b][i+1]) , ++i; 75 while( i > 1 && rt[b][i] < rt[b][i-1] ) 76 swap(rt[b][i],rt[b][i-1]) , --i; 77 } 78 inline void ins(int tar,int nv) { 79 int b,pp; 80 getp(tar,b,pp); 81 for(int i=siz[b]+1;i>pp;i--) 82 sou[b][i] = sou[b][i-1]; 83 rt[b][++siz[b]] = sou[b][pp] = nv; 84 for(int i=siz[b]; i > 1 && rt[b][i] < rt[b][i-1] ;i--) 85 swap(rt[b][i],rt[b][i-1]); 86 if( siz[b] >= ( blk << 1 ) ) { 87 nxt[++sc] = nxt[b] , 88 nxt[b] = sc; 89 for(int i=1;i<=blk;i++) 90 sou[sc][i] = sou[b][i+blk] , 91 sou[b][i+blk] = rt[b][i+blk] = 0; 92 siz[b] = siz[sc] = blk; 93 reb(b) , reb(sc); 94 } 95 } 96 97 int main() { 98 static char com[10]; 99 scanf("%d",&n); 100 for(int i=1;i<=n;i++) { 101 if( used < i ) { 102 lastp = used , used = min( used + blk , n ); 103 siz[++sc] = used - lastp; 104 if( sc != 1 ) 105 nxt[sc-1] = sc; 106 } 107 scanf("%d",&sou[sc][i-lastp]); 108 } 109 for(int i=1;i<=sc;i++) 110 reb(i); 111 scanf("%d",&m); 112 for(int i=1,l,r,k,u,p;i<=m;i++) { 113 scanf("%s",com); 114 if( *com == 'I' ) { 115 scanf("%d%d",&p,&u); 116 p ^= lastans , u ^= lastans; 117 ins(p,u); 118 } 119 else if( *com == 'M' ) { 120 scanf("%d%d",&p,&u); 121 p ^= lastans , u ^= lastans; 122 upd(p,u); 123 } 124 else if( *com == 'Q' ) { 125 scanf("%d%d%d",&l,&r,&k); 126 l ^= lastans , r ^= lastans , k ^= lastans; 127 printf("%d\n",lastans=kth(l,r,k)); 128 } 129 } 130 return 0; 131 }