اولین باره که به کاهو میای؟ راهنمای سایت رو حتما بخون!

ورود ثبت‌نام راهنما درباره‌ی کاهو
پرسش‌ها برچسب‌ها کاربر‌ها سوال بپرسید!

آمار پرسش:

  • پرسیده شده: 2018-09-01 09:08:29 -0500
  • مشاهده شده: 1,043 بار
  • بروز شده: 2019-07-28 04:29:33 -0500

پرسش‌های مشابه:

تخمین رتبه-۲۴امین دوره المپیاد کامپیوتر - آزمون دوم - :

بازی رنگی - سوال ۱ - مرحله ۲ - ۱۳۹۳

وزنه‌ها و ماشین جادویی - سوال ۲ - مرحله ۲ - ۱۳۹۳

گاوی خسیس - سوال ۳ - مرحله ۲ - ۱۳۹۳

انتقال مهره‌های گاوی - سوال ۴ - مرحله ۲ - ۱۳۹۳

سوال دوم مرحله سوم دوره 24: عبور از سد دفاعی ایران (حل شد + کد)

سوا ل 1 مرحله 3 دوره ی 24 درخت گاوی

سوال 2 مرحله 3 دوره ی 24 روز اول عبور از سد دفاعی ایران!

راس‌های رنگی - دوره‌ی تابستان

سوالات_المپیاد:دوره‌ی_تابستان:دوره‌ی_۲۴:عملی_مقدماتی_دوم:سوال_۲

نکاتی در مورد نوشتن پاسخ:

در این قسمت می‌تونی به یک پرسش پاسخ بدی. اگه می‌خوای در مورد پرسش بحث و اظهار نظر کنی از قسمت «ثبت نظر» استفاده کن.
پاسخت رو دقیق و کامل بنویس، از عکس استفاده کن و اگه لازمه به منابع (کتاب یا سایت) ارجاع بده.
اگه پرسش یا پاسخ‌ها مفید هستند حتما بهشون رای بده تا پرسش‌ها و پاسخ‌های خوب مشخص بشن.

استفاده از ویرایشگر:

توی قسمت پیش‌نمایش می‌تونی ببینی متنی که نوشتی چجوری روی سایت دیده میشه.
خیلی مهم: برای اینکه به خط بعد بری باید دوتا Enter بزنی.
می‌تونی از تگ‌های معمولی و ساده‌ی html هم استفاده کنی.
با دکمه‌هایی که بالای ویرایش‌گر قرار دارند کلی کار می‌شه کرد. از عکس‌گذاشتن بگیر تا لیست شماره‌دار. حتما امتحان‌شون کن.

علائم ریاضی:

برای نوشتن علائم ریاضی می‌تونی از Mathjax استفاده کنی. راهنمای Mathjax رو از سایت math.stackexchange بخون.
برای نوشتن عبارت ریاضی وسط جمله، اون عبارت رو بین دوتا $ قرار بده.
برای نوشتن عبارت ریاضی تو یه خط جدید اون رو بین دوتا $$ قرار بده.

مادر بزرگ - آزمون آزمایشی ۲۴ مین دوره المپیاد کامپیوتر-دوره تابستان المپیاد کامپیوتر ۱۳۹۳

7
  • محدوديت زمان: 3 ثانيه
  • محدوديت حافظه:256 مگابايت

مادربزرگ مي خواهد به مناسبت کسب مدال طلاي جهاني(fullmark) توسط تمامي $n$ نوه اش به آنها جايزه بدهد. او آنها را پشت سر هم در يک رديف و از چپ به راست نشانده است. مادربزرگ کمي حواس پرت هست و به طور ناگهاني يادش مي آيد که بايد به بازه $l$ تا $r$ از نوه هايش جايزه بدهد و براي اين کار به نفر اول(نفر $l$ ام) يک سکه به نفر بعد 2 سکه و به نفر آخر(نفر $r$ ام) $r-l+1$ سکه مي دهد.

هر از گاهي هم مادربزرگ کنجکاو است که بداند مجموع تعداد سکه هاي بازه $l$ تا $r$ از نوه هايش چقدر مي باشد.به مادربزرگ کمک کنيد!

ورودي

در خط اول ورودي دو عدد $n$ و $q$ آمده است که تعداد نوه هاي مادربزرگ و تعداد عمليات هاي مادربزرگ مي باشد!

در خط بعدي $n$ عدد آمده است که تعداد سکه هاي اوليه نوه هاي مادربزرگ به ترتيب از چپ به راست مي باشد.اين اعداد بين 0 تا $10^9$ مي باشند.

در $q$ خط بعدي در هر خط ابتدا رشته $t$ و سپس $l$ و $r$ آمده است.

اگر $t=ask$ باقيمانده مجموع تعداد سکه هاي نوه هاي بين بازه $l$ تا $r$ بر $10^9+7$ را چاپ کنيد.

اگر $t=add$ مادربزرگ به بازه ي $l$ تا $r$ از نوه هايش به شکل گفته شده سکه مي دهد.

$1\le l\le r\le n \le 200000$

$q \le 200000$

خروجي

به ازاي هر يک از عمليات هاي $ask$ جواب را چاپ کنيد.

مثال

ورودي نمونه 1

5 10
4 7 4 7 4
ask 1 5
add 1 2
ask 2 4
add 3 5
ask 4 5
add 2 5
add 3 3
ask 3 3
ask 2 5
ask 1 5

خروجي نمونه 1

26
20
16
8
41
46
داده_ساختار مقدماتی دوره۲۴ دوره-تابستون ۱۳۹۳
2018-09-01 09:08:29 -0500
غزوو 1304 ● 7 ● 14 ● 24
پاک‌کردن   ویرایش سوال

1 پاسخ

6

توضیح الگوریتم:

برای حل این سوال میتوان از داده ساختار درخت داده ها (segment tree) استفاده کرد.

در ابتدا درخت داده ای میسازیم که در هر راس آن مجموع بازه ی متناظر با آن راس نوشته شده است. میدانیم به راحتی میتوانیم مجموع یک بازه را در $O(lgn)$ به وسیله ی درخت داده ها بدست آوریم. این مقدار را برای راس شماره ی $i$ ام $tree_i$ بگیرید. ولی مشکل اصلی ما در واقع در هنگام آپدیت کردن درخت است. زیرا ممکن است بازه ی وروردی بسیار بزرگ باشد و مدت زمان زیادی برای آپدیت کردن آن طول بکشد. برای این کار آرایه ای از جفت های مرتب طراحی میکنیم که عضو $i$ام آن مرتبط با راس شماره ی $i$ درخت است. چون در هر آپدیت کردن، ما قادر به آپدیت کردن کل درخت نیستیم پس میتوانیم درون این جفت اعدادی را ذخیره کنیم که نشان دهنده ی مقداری باشد که ما باید به زیر درختی که ریشه ی آن راس مورد نظر است اضافه کنیم. (در واقع این مقدار را ذخیره میکنیم و در هنگامی که نیاز به آن داشتیم اضافه میکنیم)

در ابتدای کار تمام جفت های این آرایه $(0,0)$ هستند. فرض کنید جفت $(x,y)$ متناظر به یک راس $i$ درخت است. مقدار $x$ برابر با مقدار ثابتی است که باید به کل اعداد بازه ی متناظر اضافه شود و $y$ برابر با تعداد دفعاتی است که ما باید از اول این بازه شروع کنیم و به عضو $j$ام بازه $j$ تا اضافه کنیم.

حال چگونه مقدار ذخیره شده در آرایمان را اضافه کنیم؟ اگر در راس $i$ باشیم و طول بازه ی متناظر با راس $i$ برابر با $len$ باشد، و همچنین جفت متانظر به راس $i$ ، $(x,y)$ باشد، آنگاه به $tree_i$ مقدار زیر اضافه میگردد:

$\frac {len \times(len+1)}{2} \times y + len \times x$

بعد از این کار ما قادر نیستیم تمام زیر درخت را آپدیت کنیم در نتیجه میتوانیم جفت های متناظر به بچه های این راس را تغییر دهیم تا در هنگامی که به آنها نیازی داشتیم آنها را نیز آپدیت کنیم. اگر جفت متناظر به بچه ی سمت راست راس مورد نظر $(x_1,y_1)$ و جفت متناظر به بچه ی سمت راست این راس $(x_2,y_2)$ باشد، آنگاه این جفت ها به ترتیب به صورت زیر تغییر میکنند ($mid$ همان وسط بازه ی $i$ است. یا در واقع تعداد اعضای بازه ی متناظر با بچه ی سمت راست):

بچه ی سمت راست : $(x_1+x , y_1+y)$

بچه ی سمت چپ: $(x_2+x+mid \times y , y_2+y)$

دقت کنید مقدار $x_2$ به این دلیل $mid \times y$ اضافه شد چون شروع بازه ی سمت چپ با شروع بازه ی پدر یکسان نیست و در ابتدا باید به همه ی اعضای این بازه مقدار $mid \times y$ اضافه شود.

این عمل را ، عمل شیفت تعریف میکنیم .(یعنی اضافه کردن مقدار ذخیره ی شده ی راس $i$ به $tree_i$ و سپس آپدیت کردن جفت های بچه های آن راس)

حال میتوانیم در هنگام آپدیت کردن وقتی به یک بازه رسیدیم عمل شیف را روی آن انجام دهیم.

اما کار اصلی را هنگامی که میخواهیم مجموع اعضای یک بازه را چاپ کنیم انجام میدهیم. در اینجا هنگامی که از ریشه شروع میکنیم تا به بازه ی مورد نظر برسیم، به هر راسی که میرسیم عمل شیف را روی آن راس انجام میدهیم. در نتیجه مقدار نهایی $tree_i$ بدست می آید و ما وقتی به راس های پایین تر میرویم در واقع آنهایی را شیف میدهیم که لازم داریم، پس عملات های ما زیاد طول نمیکشد و میتوانیم در $O(lgn)$ مجموع اعضای بازه ی خواسته شده را چاپ کنیم.

حال پس در نهایت الگوریتم ما در زمان مناسب و در پیچیدگی زمانی $O(qlgn+n)$ صورت میگیرد.


توضیحات کد:

در کد تابع build درخت را میسازد، تابع update وظیفه ی آپدیت کردن بازه را دارد، تابع query مجموع بازه را به عنوان خروجی میدهد و در نهایت تابع shift عمل شیف کردن را انجام میدهد.

مشاهده ی کد (C++)

2019-02-15 04:52:40 -0500
غزوو 1304 ● 7 ● 14 ● 24
پاک‌کردن   ویرایش پاسخ
نظرات

مرسییی از توضیح ++ :)

2019-02-16 12:33:56 -0500 صفر و یک

پاسخ شما

فقط در صورتی که پاسخی برای این پرسش دارید، آن را اینجا بنویسید و برای بحث کردن از قسمت «ثبت‌ نظر» استفاده کنید. شما می‌توانید قبل از وارد شدن به سایت پاسخ خود را بنویسید. این پاسخ ذخیره می‌شود و زمانی که شما وارد سایت شدید یا ثبت‌نام کردید منتشر می‌شود.

پیش‌نمایش:

کلیه‌ی حقوق این سایت متعلق به کمیته‌ی ملی المپیاد کامپیوتر است.