20170121 机房『练习赛』
我们最好把自己的生命看做前人生命的延续,是现在共同生命的一部分,同时也后人生命的开端。如此延续下去,科学就会一天比一天灿烂,社会就会一天比一天更美好。
—— 华罗庚
我热爱生活,我是一名快速成长的OIer
目录:
T1 setsum
#define PROGRAM_NAME "setsum"
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100000+10000;
template<class TE>inline void readin(TE &res) {
char ch;
int flag=1;
while ((ch=getchar())<'0' || ch>'9') if (ch=='-') flag=-1;
res=ch-48;
while ((ch=getchar())>='0' && ch<='9')
res=(res<<1)+(res<<3)+ch-48;
res*=flag;
}
struct Node {
int sum, flag;
Node *ls, *rs;
Node(){
sum=0;
ls=NULL;
rs=NULL;
}
void pushdown(int lf, int rg) {
if (flag){
int mid=(lf+rg)>>1;
ls->sum=(mid-lf+1)*flag;
rs->sum=(rg-mid)*flag;
ls->flag=flag;
rs->flag=flag;
flag=0;
}
}
}pool[2*MAXN+1000], *tail=pool, *root;
int N, aa[MAXN];
Node *build(int lf, int rg)
{
Node *nd=++tail;
if (lf==rg) {
nd->sum=aa[lf];
}else {
int mid=(lf+rg)>>1;
nd->ls=build(lf,mid);
nd->rs=build(mid+1,rg);
nd->sum=nd->ls->sum+nd->rs->sum;
}
//printf("build:%d %d %d\n",nd-pool,lf,rg);
return nd;
}
void init()
{
readin(N);
for (int i=1; i<=N; i++) readin(aa[i]);
root=build(1,N);
}
void modify(struct Node *nd, int lf, int rg, int L, int R, int val)
{
if (L<=lf && rg<=R) {
nd->sum=(rg-lf+1)*val;
nd->flag=val;
}else {
int mid=(lf+rg)>>1;
nd->pushdown(lf,rg);
if (L<=mid) modify(nd->ls,lf,mid,L,R,val);
if (R>mid) modify(nd->rs,mid+1,rg,L,R,val);
nd->sum=nd->ls->sum+nd->rs->sum;
}
//printf("modify:%d %d %d\n",lf,rg,nd->sum);
}
int query(struct Node *nd, int lf ,int rg, int L, int R)
{
//printf("query:%d %d %d\n",nd-pool,lf,rg);
if (L<=lf && rg<=R) {
return nd->sum;
}else {
int mid=(lf+rg)>>1, td=0;
nd->pushdown(lf,rg);
if (L<=mid) td+=query(nd->ls,lf,mid,L,R);
if (R>mid) td+=query(nd->rs,mid+1,rg,L,R);
return td;
}
}
int Q, L, R, val;
char ss[100];
void solve()
{
readin(Q);
for (int i=1; i<=Q; i++)
{
scanf("%s",ss);
if (ss[0]=='m') {
readin(L);
readin(R);
readin(val);
modify(root,1,N,L,R,val);
} else {
readin(L);
readin(R);
printf("%d\n",query(root,1,N,L,R));
}
}
}
int main()
{
freopen(PROGRAM_NAME".in","r",stdin);
freopen(PROGRAM_NAME".out","w",stdout);
init();
solve();
return 0;
}
第一题最开始时0分,线段树轻轻松松破百行。区间修改,区间求和。需注意的是,flag与sum都不可再用“+=”,因为是覆盖,覆盖便意味着是“=”,但是只改了sum而未改flag。0分!将flag改了以后轻松AC,确实理解不够深入。(P.S.:上课不听非非讲,受害很深重)
时间复杂度:
O(nlogn+Qlogn)
T2 subtree
#define PROGRAM_NAME "subtree"
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100100;
const int MAXM = MAXN*2;
template<class TE>inline void readin(TE &res) {
char ch;
int flag=1;
while ((ch=getchar())<'0' || ch>'9') if (ch=='-') flag=-1;
res=ch-48;
while ((ch=getchar())>='0' && ch<='9')
res=(res<<1)+(res<<3)+ch-48;
res*=flag;
}
struct Node {
long long sum;
Node *ls, *rs;
Node(){
sum=0;
ls=NULL;
rs=NULL;
}
}pool[2*MAXN+1000], *tail=pool, *root;
int N;
long long aa[MAXN];
struct Edge
{
int v, next;
}t[MAXM+1000];
int num=0, head[MAXN];
inline void insert(int u, int v)
{
t[++num].v=v;
t[num].next=head[u];
head[u]=num;
}
int in[MAXN], out[MAXN], order[MAXN], INDEX=0;
void dfs(int u, int f)
{
in[u]=++INDEX;
order[INDEX]=u;
//printf("DFS:%d %d %d\n",u,f,in[u]);
for (int i=head[u]; i!=0; i=t[i].next) if (t[i].v!=f) dfs(t[i].v,u);
out[u]=INDEX;
}
Node *build(int lf, int rg)
{
Node *nd=++tail;
if (lf==rg) {
nd->sum=aa[order[lf]];
//printf("BUILD:%d %d %d\n",lf,in[lf],aa[in[lf]]);
}else {
int mid=(lf+rg)>>1;
nd->ls=build(lf,mid);
nd->rs=build(mid+1,rg);
nd->sum=nd->ls->sum+nd->rs->sum;
}
//printf("build:%d %d %d\n",lf,rg,nd->sum);
return nd;
}
int u, v;
void init()
{
memset(head,0,sizeof(head));
readin(N);
for (int i=1; i<=N; i++) readin(aa[i]);
for (int i=1; i<=N-1; i++)
{
readin(u);
readin(v);
insert(u,v);
insert(v,u);
}
dfs(1,0);
//for (int i=1; i<=N; i++) printf("%d ",in[i]);printf("\n");
//for (int i=1; i<=N; i++) printf("%d ",out[i]);printf("\n");
root=build(1,N);
}
void modify(struct Node *nd, int lf, int rg, int pos, int val)
{
if (lf==rg) {
nd->sum+=val;
//printf("modify:%d %d %d %d\n",lf,rg,val,nd->sum);
}else {
int mid=(lf+rg)>>1;
if (pos<=mid) modify(nd->ls,lf,mid,pos,val);
else modify(nd->rs,mid+1,rg,pos,val);
nd->sum=nd->ls->sum+nd->rs->sum;
}
//printf("modify:%d %d %d\n",lf,rg,nd->sum);
}
long long query(struct Node *nd, int lf ,int rg, int L, int R)
{
//printf("query:%d %d %d\n",nd-pool,lf,rg);
if (L<=lf && rg<=R) {
return nd->sum;
}else {
int mid=(lf+rg)>>1;
long long td=0;
if (L<=mid) td+=query(nd->ls,lf,mid,L,R);
if (R>mid) td+=query(nd->rs,mid+1,rg,L,R);
return td;
}
}
int Q, pos, val, L, R;
char ss[100];
void solve()
{
readin(Q);
for (int i=1; i<=Q; i++)
{
scanf("%s",ss);
if (ss[0]=='m') {
readin(pos);
readin(val);
modify(root,1,N,in[pos],val);
} else {
readin(pos);
cout << query(root,1,N,in[pos],out[pos]) << endl;
}
}
}
int main()
{
freopen(PROGRAM_NAME".in","r",stdin);
freopen(PROGRAM_NAME".out","w",stdout);
init();
solve();
return 0;
}
第二题开始只有30分,树套线段树。先前向星,再DFS求in和out,根据in的值确定节点位置,建树时节点加点权,修改单点,查询in与out构成的区间。单点修改点权,子树求和。需深入理解DFS序。(就是MAXN开的不够,血的教训!)
时间复杂度:
O(nlogn+Qlogn)
T3 matgcd
#define PROGRAM_NAME "matgcd"
#include <cstdio>
#include <ctime>
const int MAXN = 500+10;
const int MAXM = MAXN;
const int LOGM = 9+1;
const int MAXQ = 100000;
template<class TE>inline void readin(TE &res) {
char ch;int flag=1;
while ((ch=getchar())<'0' || ch>'9') if (ch=='-') flag=-1;res=ch-48;
while ((ch=getchar())>='0' && ch<='9') res=(res<<1)+(res<<3)+ch-48;
res*=flag;
}
inline int gcd(int x, int y){while (1){if (y==0) return x;int b=x;x=y;y=b%y;}}
const int pow2[]={1,2,4,8,16,32,64,128,256,512};
inline int log2(int n){for (int i=0; i<=9; i++) if (pow2[i+1]>n) return i;}
int N, M, Q, a, b, c, d, log2N, log2M;
int f[MAXN][10][MAXM][10];
void init()
{
readin(N);
readin(M);
readin(Q);
for (int i=1; i<=N; i++)
for (int j=1; j<=M; j++)
readin(f[i][0][j][0]);
log2N=log2(N);
log2M=log2(M);
for (int j=1; j<=log2M; j++)
for (int x=1; x<=N; x++)
for (int y=1; y<=M-pow2[j]+1; y++)
{
a=f[x][0][y][j-1];
b=f[x][0][y+pow2[j-1]][j-1];
f[x][0][y][j]=gcd(a,b);
}
for (int i=1; i<=log2N; i++)
for (int x=1; x<=N-pow2[i]+1; x++)
for (int y=1; y<=M; y++)
{
a=f[x][i-1][y][0];
b=f[x+pow2[i-1]][i-1][y][0];
f[x][i][y][0]=gcd(a,b);
}
for (int i=1; i<=log2N; i++)
for (int j=1; j<=log2M; j++)
for (int x=1; x<=N-pow2[i]+1; x++)
for (int y=1; y<=M-pow2[j]+1; y++)
{
a=f[x][i-1][y][j-1];
b=f[x+pow2[i-1]][i-1][y][j-1];
c=f[x][i-1][y+pow2[j-1]][j-1];
d=f[x+pow2[i-1]][i-1][y+pow2[j-1]][j-1];
f[x][i][y][j]=gcd(gcd(gcd(a,b),c),d);
}
}
int q, x1, x2, y1, y2;
char ss[100];
void solve()
{
for (int i=1; i<=Q; i++)
{
scanf("%s",ss);
readin(x1);
readin(y1);
readin(x2);
readin(y2);
log2N=log2(x2-x1+1);
log2M=log2(y2-y1+1);
a=f[x1][log2N][y1][log2M];
b=f[x2-pow2[log2N]+1][log2N][y1][log2M];
c=f[x1][log2N][y2-pow2[log2M]+1][log2M];
d=f[x2-pow2[log2N]+1][log2N][y2-pow2[log2M]+1][log2M];
printf("%d\n",gcd(gcd(gcd(a,b),c),d));
}
}
int main()
{
freopen(PROGRAM_NAME".in","r",stdin);
freopen(PROGRAM_NAME".out","w",stdout);
init();
solve();
return 0;
}
第三题开始仅30分,ST表。之前仅用3维,时间复杂度很大,为
O(nlog2n+nQ)
。当Q达到足够大小时,准超时。而开成四维以后,虽预处理较烦,但能轻松应付Q。
时间复杂度:
O((nlogn)2+Q)
经验与教训
这一次第一回仅60分,而第二回便升至240分,第三回终于修成正果(300-240=60爆数组,T2只开了100000而无“+…”)。在较复杂的数据结构中,任意一个小错误都能产生致命的伤害(例如左右子树搞混,未返回值,修改方法不对。。。),故很有必要建模版。叶余非提前交卷210,再改便又AK。叶余非很强,可以好好仰望他,好好请教他。
附录1: 大神与非大神的blog
Websites | Belonging to | P.S. |
---|---|---|
idy002 - 丁尧尧 | cnblogs | 高新的荣耀 |
lflame - 杨雅儒 | lofter | OMG |
yjq_naive - 杨景钦 | lofter | 国家集训队选手 |
阿波罗2003 - yyf | cnblogs | 萌萌的小东西 |
mcfx - wsq | 自建 | 必成大器 |
hzwer - 黄学长 | 自建 | 无需多言 |
董的博客 | 自建 | 入门教程必读 |
林荫高16级信竞公共博客 | CSDN | 强! |
deadshotz - 程sz | cnblogs | 就是个高二的 |
lemonoil - lmy | CSDN | 有待追赶 |
lemonoil - lmy | cnblogs | 小号 |
Doggu - gyk | CSDN | 呵呵 |
Doggu - gyk | cnblogs | 精美小号 |
maverickfw - wyy | CSDN | FAT |