18 2 11 刷題心得

2021-08-15 14:29:30 字數 4811 閱讀 8761

本來今天要學fft的,結果還是沒看下去。。。看來達到我智商的瓶頸了qaq

題目cqoi2011 動態逆序對

比較裸的樹狀陣列套線段樹,然而還是卡了我好久。

因為這題很友好所以不用離散化;

以位置為主席樹的時間軸,權值為主席樹上的區間建樹;

那麼每次加乙個數的時候的貢獻就是之前出現的數中值比這個數大的個數;

對於修改,套乙個樹狀陣列,將修改的位置對之後的影響用樹狀陣列全部消掉;

對於每次修改產生的影響,需要查詢小於這個位置中所有大於這個數的和,由於樹狀陣列只能保證字首和的性質,對於區間查詢其實可以想普通線段樹那樣進行查詢,但是不怎麼會傳遞陣列,就查詢了兩個端點的字首和再相減;

而查詢大於這個數的位置且小於這個數的和的時候外邊也要有一層差分,即所有位置小於這個數的和減去這個位置之前小於這個數的和;

我也不知道怎麼著就過了這個題,還是多打點注釋吧orz

#include

#include

#include

#include

#include

#include

#define ll long long

#define random(a,b) (a+rand()%(b-a+1))

const int maxn=100005;

int n,m;

int a[maxn];

int too[maxn];

ints[maxn];

int root[maxn];

int ntot=0;

intlc[maxn];

int lowbit(int

x)struct asd

t[maxn*100];

int build(int l,int r,int

y,int

pos,int v)

return tmp;

}int tp;

ll ans=0;

void del(int

pos,int v)

int query(int l,int r,int

x,int

pos)

else

}for(int i=x;i;i-=lowbit(i))tans+=t[too[i]].sum;//這裡加的值是當前區間被修改的量

tans+=t[nrt].sum;

return tans;

}int findv(int

x,int nl,int nr)

intread()

return tmp;

}int main()

for(int i=1;i<=n;i++)

printf("%lld\n",ans);

for(int i=1;ireturn

0;

}

題目:bzoj 2653 middle
#include

#include

#include

#include

#include

#define ll long long

#define random(a,b) (a+rand()%(b-a+1))

const

int maxn=20005;

int n,m;

using

std::max;

struct asd

t[maxn*40];

int ntot=0;

int root[maxn];

void updata(int x)

void build(int l,int r,int &x)

int mid=(l+r)>>1;

build(l,mid,t[x].l);

build(mid+1,r,t[x].r);

updata(x);

}void insert(int l,int r,int &x,int y,int pos,int v)

int mid=(l+r)>>1;

if(pos<=mid)insert(l,mid,t[x].l,t[y].l,pos,v);

else insert(mid+1,r,t[x].r,t[y].r,pos,v);

updata(x);

}int querysum(int l,int r,int x,int nl,int nr)

int querylmax(int l,int r,int x,int nl,int nr)

int queryrmax(int l,int r,int x,int nl,int nr)

int findans(int x,int u,int v,int y)

return a[tans].v;

}int tp[4],q;

int main()

build(1,n,root[0]);

std::sort(a+1,a+n+1);

for(int i=1;i<=n;i++)

insert(1,n,root[i],root[i-1],a[i].lc,-1);//將這個數的位置上的值標為-1;

scanf("%d",&q);

int la=0;

for(int i=1;i<=q;i++)

std::sort(tp,tp+4);

printf("%d\n",la=findans(tp[0],tp[1],tp[2],tp[3]));

}return

0;

}

題目:scoi2014 旅行

一道比較好想的樹鏈剖分加線段樹做法,而且只需要單點修改和區間求和以及求最值;

給每一種顏色建一顆線段樹,一開始並沒有任何節點,進行動態開點;

將所有節點其所對應顏色的線段樹上的對應位置加上這個點的權值,每一次修改時空都是logn

對於修改操作,如果改顏色,將當前顏色線段樹上的值設為0,新顏色線段樹上的值加上這個節點的權值

如果改權值,直接改對應顏色線段樹上的值,不要忘了陣列中的值也要改;

剩下的就是樹剖的常見操作了

我比較閒的是,線段樹不想寫遞迴版的,於是記了線段樹上每個點的父親,修改完之後再倒著updata一下,中間還手殘了調了很久。。。

#include

#include

#include

#include

#include

#define ll long long

#define random(a,b) (a+rand()%(b-a+1))

int n,q;

using

std::max;

using

std::swap;

const

int maxn=100005;

int tp1,tp2;

int node[maxn];

int siz[maxn],d[maxn],start[maxn],tp[maxn],fa[maxn],son[maxn];

int a[maxn],b[maxn],c[maxn];

int rt[maxn];

struct qwe

}t[maxn*40];

struct asd

edge[maxn*2];

int etot=0;

void add(int x,int y)

int dfs(int x)

int tot=0;

void dfs1(int x,int top)

int ntot=0;

void modify(int x,int pos,int v)

else

}t[x].lv=t[x].rv=l;

t[x].sum=t[x].mv=v;

while(x=t[x].fa)

}int query(int l,int r,int x,int nl,int nr,int check)

int mid=(l+r)>>1;

int ans=0;

if(nl<=mid&&t[x].l)

if(nr>mid&&t[x].r)

return ans;

}int findans(int x,int y,int check)

if(d[x]if(check)

ans+=query(1,n,rt[tc],start[y],start[x],check);

else ans=max(ans,query(1,n,rt[tc],start[y],start[x],check));

}return ans;

}int main()

for(int i=1;iscanf("%d%d",&tp1,&tp2);

add(tp1,tp2);

add(tp2,tp1);

} dfs(1);

dfs1(1,1);

for(int i=1;i<=100000;i++)rt[i]=i;

ntot=100000;

for(int i=1;i<=n;i++)

modify(rt[c[i]],start[i],a[i]);

char s[5];

while(q--)

else

if(s[1]=='w')

else

if(s[1]=='s')

printf("%d\n",findans(tp1,tp2,1));

else

printf("%d\n",findans(tp1,tp2,0));

}return

0;}

SQL刷題心得

題目 給定乙個 salary 表,如下所示,有 m 男性 和 f 女性 的值。交換所有的 f 和 m 值 例如,將所有 f 值更改為 m,反之亦然 要求只使用乙個更新 update 語句,並且沒有中間的臨時表。update 表名稱 set 列名稱 新值 where 列名稱 某值 update sal...

leetcode刷題心得分享

知道了這些規則之後,就能知道該如何轉換羅馬數字了。舉個例子,將99轉化為羅馬數字,乍一看好像是ic,因為右邊的大數減去跟著的小數為 c 100 i 1 99,但違反了第4個規則,所以正確的表示方式應該是xcix,至於為什麼不是ixxc,是因為要將大的數放在左邊,好了講了一堆羅馬數字的表示規則,該貼出...

LeetCode刷題心得 整數反轉

整數反 如果想得到乙個32位整數x中的每乙個數字,可以採用如下演算法 int pop x 10 x 10 這個演算法的意思就是,先pop得到x除以10取餘後的結果,然後x再往後退一位。例如x 123,則第一步pop 3,然後x變為12,第二步就是pop 2,x變為1,最後一步則pop 1,x 0.迴...